diff --git a/.github/ISSUE_TEMPLATE/tracking_issue.md b/.github/ISSUE_TEMPLATE/tracking_issue.md index f93591204cd..9457cce11af 100644 --- a/.github/ISSUE_TEMPLATE/tracking_issue.md +++ b/.github/ISSUE_TEMPLATE/tracking_issue.md @@ -36,11 +36,11 @@ for larger features an implementation could be broken up into multiple PRs. - [ ] Implement the RFC (cc @rust-lang/XXX -- can anyone write up mentoring instructions?) -- [ ] Adjust documentation ([see instructions on rustc-guide][doc-guide]) -- [ ] Stabilization PR ([see instructions on rustc-guide][stabilization-guide]) +- [ ] Adjust documentation ([see instructions on rustc-dev-guide][doc-guide]) +- [ ] Stabilization PR ([see instructions on rustc-dev-guide][stabilization-guide]) -[stabilization-guide]: https://rust-lang.github.io/rustc-guide/stabilization_guide.html#stabilization-pr -[doc-guide]: https://rust-lang.github.io/rustc-guide/stabilization_guide.html#documentation-prs +[stabilization-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#stabilization-pr +[doc-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#documentation-prs ### Unresolved Questions recursive at depth {}", - stack.fresh_trait_ref, cycle_depth, - ); - - // If we have a stack like `A B C D E A`, where the top of - // the stack is the final `A`, then this will iterate over - // `A, E, D, C, B` -- i.e., all the participants apart - // from the cycle head. We mark them as participating in a - // cycle. This suppresses caching for those nodes. See - // `in_cycle` field for more details. - stack.update_reached_depth(cycle_depth); - - // Subtle: when checking for a coinductive cycle, we do - // not compare using the "freshened trait refs" (which - // have erased regions) but rather the fully explicit - // trait refs. This is important because it's only a cycle - // if the regions match exactly. - let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth); - let cycle = cycle.map(|stack| { - ty::Predicate::Trait(stack.obligation.predicate, hir::Constness::NotConst) - }); - if self.coinductive_match(cycle) { - debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); - Some(EvaluatedToOk) - } else { - debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref); - Some(EvaluatedToRecur) - } - } else { - None - } - } - - fn evaluate_stack<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> Result { - // In intercrate mode, whenever any of the types are unbound, - // there can always be an impl. Even if there are no impls in - // this crate, perhaps the type would be unified with - // something from another crate that does provide an impl. - // - // In intra mode, we must still be conservative. The reason is - // that we want to avoid cycles. Imagine an impl like: - // - // impl Eq for Vec - // - // and a trait reference like `$0 : Eq` where `$0` is an - // unbound variable. When we evaluate this trait-reference, we - // will unify `$0` with `Vec<$1>` (for some fresh variable - // `$1`), on the condition that `$1 : Eq`. We will then wind - // up with many candidates (since that are other `Eq` impls - // that apply) and try to winnow things down. This results in - // a recursive evaluation that `$1 : Eq` -- as you can - // imagine, this is just where we started. To avoid that, we - // check for unbound variables and return an ambiguous (hence possible) - // match if we've seen this trait before. - // - // This suffices to allow chains like `FnMut` implemented in - // terms of `Fn` etc, but we could probably make this more - // precise still. - let unbound_input_types = - stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh()); - // This check was an imperfect workaround for a bug in the old - // intercrate mode; it should be removed when that goes away. - if unbound_input_types && self.intercrate { - debug!( - "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", - stack.fresh_trait_ref - ); - // Heuristics: show the diagnostics when there are no candidates in crate. - if self.intercrate_ambiguity_causes.is_some() { - debug!("evaluate_stack: intercrate_ambiguity_causes is some"); - if let Ok(candidate_set) = self.assemble_candidates(stack) { - if !candidate_set.ambiguous && candidate_set.vec.is_empty() { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let cause = IntercrateAmbiguityCause::DownstreamCrate { - trait_desc: trait_ref.print_only_trait_path().to_string(), - self_desc: if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }, - }; - debug!("evaluate_stack: pushing cause = {:?}", cause); - self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); - } - } - } - return Ok(EvaluatedToAmbig); - } - if unbound_input_types - && stack.iter().skip(1).any(|prev| { - stack.obligation.param_env == prev.obligation.param_env - && self.match_fresh_trait_refs( - &stack.fresh_trait_ref, - &prev.fresh_trait_ref, - prev.obligation.param_env, - ) - }) - { - debug!( - "evaluate_stack({:?}) --> unbound argument, recursive --> giving up", - stack.fresh_trait_ref - ); - return Ok(EvaluatedToUnknown); - } - - match self.candidate_from_obligation(stack) { - Ok(Some(c)) => self.evaluate_candidate(stack, &c), - Ok(None) => Ok(EvaluatedToAmbig), - Err(Overflow) => Err(OverflowError), - Err(..) => Ok(EvaluatedToErr), - } - } - - /// For defaulted traits, we use a co-inductive strategy to solve, so - /// that recursion is ok. This routine returns `true` if the top of the - /// stack (`cycle[0]`): - /// - /// - is a defaulted trait, - /// - it also appears in the backtrace at some position `X`, - /// - all the predicates at positions `X..` between `X` and the top are - /// also defaulted traits. - pub fn coinductive_match(&mut self, cycle: I) -> bool - where - I: Iterator>, - { - let mut cycle = cycle; - cycle.all(|predicate| self.coinductive_predicate(predicate)) - } - - fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { - let result = match predicate { - ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), - _ => false, - }; - debug!("coinductive_predicate({:?}) = {:?}", predicate, result); - result - } - - /// Further evaluates `candidate` to decide whether all type parameters match and whether nested - /// obligations are met. Returns whether `candidate` remains viable after this further - /// scrutiny. - fn evaluate_candidate<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - candidate: &SelectionCandidate<'tcx>, - ) -> Result { - debug!( - "evaluate_candidate: depth={} candidate={:?}", - stack.obligation.recursion_depth, candidate - ); - let result = self.evaluation_probe(|this| { - let candidate = (*candidate).clone(); - match this.confirm_candidate(stack.obligation, candidate) { - Ok(selection) => this.evaluate_predicates_recursively( - stack.list(), - selection.nested_obligations().into_iter(), - ), - Err(..) => Ok(EvaluatedToErr), - } - })?; - debug!( - "evaluate_candidate: depth={} result={:?}", - stack.obligation.recursion_depth, result - ); - Ok(result) - } - - fn check_evaluation_cache( - &self, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Option { - let tcx = self.tcx(); - if self.can_use_global_caches(param_env) { - let cache = tcx.evaluation_cache.hashmap.borrow(); - if let Some(cached) = cache.get(¶m_env.and(trait_ref)) { - return Some(cached.get(tcx)); - } - } - self.infcx - .evaluation_cache - .hashmap - .borrow() - .get(¶m_env.and(trait_ref)) - .map(|v| v.get(tcx)) - } - - fn insert_evaluation_cache( - &mut self, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - dep_node: DepNodeIndex, - result: EvaluationResult, - ) { - // Avoid caching results that depend on more than just the trait-ref - // - the stack can create recursion. - if result.is_stack_dependent() { - return; - } - - if self.can_use_global_caches(param_env) { - if !trait_ref.has_local_value() { - debug!( - "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global", - trait_ref, result, - ); - // This may overwrite the cache with the same value - // FIXME: Due to #50507 this overwrites the different values - // This should be changed to use HashMapExt::insert_same - // when that is fixed - self.tcx() - .evaluation_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result)); - return; - } - } - - debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,); - self.infcx - .evaluation_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result)); - } - - /// For various reasons, it's possible for a subobligation - /// to have a *lower* recursion_depth than the obligation used to create it. - /// Projection sub-obligations may be returned from the projection cache, - /// which results in obligations with an 'old' `recursion_depth`. - /// Additionally, methods like `wf::obligations` and - /// `InferCtxt.subtype_predicate` produce subobligations without - /// taking in a 'parent' depth, causing the generated subobligations - /// to have a `recursion_depth` of `0`. - /// - /// To ensure that obligation_depth never decreasees, we force all subobligations - /// to have at least the depth of the original obligation. - fn add_depth>>( - &self, - it: I, - min_depth: usize, - ) { - it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); - } - - /// Checks that the recursion limit has not been exceeded. - /// - /// The weird return type of this function allows it to be used with the `try` (`?`) - /// operator within certain functions. - fn check_recursion_limit, V: Display + TypeFoldable<'tcx>>( - &self, - obligation: &Obligation<'tcx, T>, - error_obligation: &Obligation<'tcx, V>, - ) -> Result<(), OverflowError> { - let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); - if obligation.recursion_depth >= recursion_limit { - match self.query_mode { - TraitQueryMode::Standard => { - self.infcx().report_overflow_error(error_obligation, true); - } - TraitQueryMode::Canonical => { - return Err(OverflowError); - } - } - } - Ok(()) - } - - /////////////////////////////////////////////////////////////////////////// - // CANDIDATE ASSEMBLY - // - // The selection process begins by examining all in-scope impls, - // caller obligations, and so forth and assembling a list of - // candidates. See the [rustc guide] for more details. - // - // [rustc guide]: - // https://rust-lang.github.io/rustc-guide/traits/resolution.html#candidate-assembly - - fn candidate_from_obligation<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - // Watch out for overflow. This intentionally bypasses (and does - // not update) the cache. - self.check_recursion_limit(&stack.obligation, &stack.obligation)?; - - // Check the cache. Note that we freshen the trait-ref - // separately rather than using `stack.fresh_trait_ref` -- - // this is because we want the unbound variables to be - // replaced with fresh types starting from index 0. - let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate.clone()); - debug!( - "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})", - cache_fresh_trait_pred, stack - ); - debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars()); - - if let Some(c) = - self.check_candidate_cache(stack.obligation.param_env, &cache_fresh_trait_pred) - { - debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c); - return c; - } - - // If no match, compute result and insert into cache. - // - // FIXME(nikomatsakis) -- this cache is not taking into - // account cycles that may have occurred in forming the - // candidate. I don't know of any specific problems that - // result but it seems awfully suspicious. - let (candidate, dep_node) = - self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); - - debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate); - self.insert_candidate_cache( - stack.obligation.param_env, - cache_fresh_trait_pred, - dep_node, - candidate.clone(), - ); - candidate - } - - fn in_task(&mut self, op: OP) -> (R, DepNodeIndex) - where - OP: FnOnce(&mut Self) -> R, - { - let (result, dep_node) = - self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || op(self)); - self.tcx().dep_graph.read_index(dep_node); - (result, dep_node) - } - - // Treat negative impls as unimplemented, and reservation impls as ambiguity. - fn filter_negative_and_reservation_impls( - &mut self, - candidate: SelectionCandidate<'tcx>, - ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if let ImplCandidate(def_id) = candidate { - let tcx = self.tcx(); - match tcx.impl_polarity(def_id) { - ty::ImplPolarity::Negative if !self.allow_negative_impls => { - return Err(Unimplemented); - } - ty::ImplPolarity::Reservation => { - if let Some(intercrate_ambiguity_clauses) = - &mut self.intercrate_ambiguity_causes - { - let attrs = tcx.get_attrs(def_id); - let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl); - let value = attr.and_then(|a| a.value_str()); - if let Some(value) = value { - debug!( - "filter_negative_and_reservation_impls: \ - reservation impl ambiguity on {:?}", - def_id - ); - intercrate_ambiguity_clauses.push( - IntercrateAmbiguityCause::ReservationImpl { - message: value.to_string(), - }, - ); - } - } - return Ok(None); - } - _ => {} - }; - } - Ok(Some(candidate)) - } - - fn candidate_from_obligation_no_cache<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if stack.obligation.predicate.references_error() { - // If we encounter a `Error`, we generally prefer the - // most "optimistic" result in response -- that is, the - // one least likely to report downstream errors. But - // because this routine is shared by coherence and by - // trait selection, there isn't an obvious "right" choice - // here in that respect, so we opt to just return - // ambiguity and let the upstream clients sort it out. - return Ok(None); - } - - if let Some(conflict) = self.is_knowable(stack) { - debug!("coherence stage: not knowable"); - if self.intercrate_ambiguity_causes.is_some() { - debug!("evaluate_stack: intercrate_ambiguity_causes is some"); - // Heuristics: show the diagnostics when there are no candidates in crate. - if let Ok(candidate_set) = self.assemble_candidates(stack) { - let mut no_candidates_apply = true; - { - let evaluated_candidates = - candidate_set.vec.iter().map(|c| self.evaluate_candidate(stack, &c)); - - for ec in evaluated_candidates { - match ec { - Ok(c) => { - if c.may_apply() { - no_candidates_apply = false; - break; - } - } - Err(e) => return Err(e.into()), - } - } - } - - if !candidate_set.ambiguous && no_candidates_apply { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }; - let cause = if let Conflict::Upstream = conflict { - IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } - } else { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } - }; - debug!("evaluate_stack: pushing cause = {:?}", cause); - self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); - } - } - } - return Ok(None); - } - - let candidate_set = self.assemble_candidates(stack)?; - - if candidate_set.ambiguous { - debug!("candidate set contains ambig"); - return Ok(None); - } - - let mut candidates = candidate_set.vec; - - debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); - - // At this point, we know that each of the entries in the - // candidate set is *individually* applicable. Now we have to - // figure out if they contain mutual incompatibilities. This - // frequently arises if we have an unconstrained input type -- - // for example, we are looking for `$0: Eq` where `$0` is some - // unconstrained type variable. In that case, we'll get a - // candidate which assumes $0 == int, one that assumes `$0 == - // usize`, etc. This spells an ambiguity. - - // If there is more than one candidate, first winnow them down - // by considering extra conditions (nested obligations and so - // forth). We don't winnow if there is exactly one - // candidate. This is a relatively minor distinction but it - // can lead to better inference and error-reporting. An - // example would be if there was an impl: - // - // impl Vec { fn push_clone(...) { ... } } - // - // and we were to see some code `foo.push_clone()` where `boo` - // is a `Vec` and `Bar` does not implement `Clone`. If - // we were to winnow, we'd wind up with zero candidates. - // Instead, we select the right impl now but report "`Bar` does - // not implement `Clone`". - if candidates.len() == 1 { - return self.filter_negative_and_reservation_impls(candidates.pop().unwrap()); - } - - // Winnow, but record the exact outcome of evaluation, which - // is needed for specialization. Propagate overflow if it occurs. - let mut candidates = candidates - .into_iter() - .map(|c| match self.evaluate_candidate(stack, &c) { - Ok(eval) if eval.may_apply() => { - Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) - } - Ok(_) => Ok(None), - Err(OverflowError) => Err(Overflow), - }) - .flat_map(Result::transpose) - .collect::, _>>()?; - - debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); - - let needs_infer = stack.obligation.predicate.needs_infer(); - - // If there are STILL multiple candidates, we can further - // reduce the list by dropping duplicates -- including - // resolving specializations. - if candidates.len() > 1 { - let mut i = 0; - while i < candidates.len() { - let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { - self.candidate_should_be_dropped_in_favor_of( - &candidates[i], - &candidates[j], - needs_infer, - ) - }); - if is_dup { - debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); - candidates.swap_remove(i); - } else { - debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); - i += 1; - - // If there are *STILL* multiple candidates, give up - // and report ambiguity. - if i > 1 { - debug!("multiple matches, ambig"); - return Ok(None); - } - } - } - } - - // If there are *NO* candidates, then there are no impls -- - // that we know of, anyway. Note that in the case where there - // are unbound type variables within the obligation, it might - // be the case that you could still satisfy the obligation - // from another crate by instantiating the type variables with - // a type from another crate that does have an impl. This case - // is checked for in `evaluate_stack` (and hence users - // who might care about this case, like coherence, should use - // that function). - if candidates.is_empty() { - return Err(Unimplemented); - } - - // Just one candidate left. - self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate) - } - - fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option { - debug!("is_knowable(intercrate={:?})", self.intercrate); - - if !self.intercrate { - return None; - } - - let obligation = &stack.obligation; - let predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); - - // Okay to skip binder because of the nature of the - // trait-ref-is-knowable check, which does not care about - // bound regions. - let trait_ref = predicate.skip_binder().trait_ref; - - coherence::trait_ref_is_knowable(self.tcx(), trait_ref) - } - - /// Returns `true` if the global caches can be used. - /// Do note that if the type itself is not in the - /// global tcx, the local caches will be used. - fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool { - // If there are any e.g. inference variables in the `ParamEnv`, then we - // always use a cache local to this particular scope. Otherwise, we - // switch to a global cache. - if param_env.has_local_value() { - return false; - } - - // Avoid using the master cache during coherence and just rely - // on the local cache. This effectively disables caching - // during coherence. It is really just a simplification to - // avoid us having to fear that coherence results "pollute" - // the master cache. Since coherence executes pretty quickly, - // it's not worth going to more trouble to increase the - // hit-rate, I don't think. - if self.intercrate { - return false; - } - - // Otherwise, we can use the global cache. - true - } - - fn check_candidate_cache( - &mut self, - param_env: ty::ParamEnv<'tcx>, - cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>, - ) -> Option>> { - let tcx = self.tcx(); - let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref; - if self.can_use_global_caches(param_env) { - let cache = tcx.selection_cache.hashmap.borrow(); - if let Some(cached) = cache.get(¶m_env.and(*trait_ref)) { - return Some(cached.get(tcx)); - } - } - self.infcx - .selection_cache - .hashmap - .borrow() - .get(¶m_env.and(*trait_ref)) - .map(|v| v.get(tcx)) - } - - /// Determines whether can we safely cache the result - /// of selecting an obligation. This is almost always `true`, - /// except when dealing with certain `ParamCandidate`s. - /// - /// Ordinarily, a `ParamCandidate` will contain no inference variables, - /// since it was usually produced directly from a `DefId`. However, - /// certain cases (currently only librustdoc's blanket impl finder), - /// a `ParamEnv` may be explicitly constructed with inference types. - /// When this is the case, we do *not* want to cache the resulting selection - /// candidate. This is due to the fact that it might not always be possible - /// to equate the obligation's trait ref and the candidate's trait ref, - /// if more constraints end up getting added to an inference variable. - /// - /// Because of this, we always want to re-run the full selection - /// process for our obligation the next time we see it, since - /// we might end up picking a different `SelectionCandidate` (or none at all). - fn can_cache_candidate( - &self, - result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, - ) -> bool { - match result { - Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => { - !trait_ref.skip_binder().input_types().any(|t| t.walk().any(|t_| t_.is_ty_infer())) - } - _ => true, - } - } - - fn insert_candidate_cache( - &mut self, - param_env: ty::ParamEnv<'tcx>, - cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, - dep_node: DepNodeIndex, - candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>, - ) { - let tcx = self.tcx(); - let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref; - - if !self.can_cache_candidate(&candidate) { - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?} -\ - candidate is not cacheable", - trait_ref, candidate - ); - return; - } - - if self.can_use_global_caches(param_env) { - if let Err(Overflow) = candidate { - // Don't cache overflow globally; we only produce this in certain modes. - } else if !trait_ref.has_local_value() { - if !candidate.has_local_value() { - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?}) global", - trait_ref, candidate, - ); - // This may overwrite the cache with the same value. - tcx.selection_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate)); - return; - } - } - } - - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?}) local", - trait_ref, candidate, - ); - self.infcx - .selection_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate)); - } - - fn assemble_candidates<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> Result, SelectionError<'tcx>> { - let TraitObligationStack { obligation, .. } = *stack; - let ref obligation = Obligation { - param_env: obligation.param_env, - cause: obligation.cause.clone(), - recursion_depth: obligation.recursion_depth, - predicate: self.infcx().resolve_vars_if_possible(&obligation.predicate), - }; - - if obligation.predicate.skip_binder().self_ty().is_ty_var() { - // Self is a type variable (e.g., `_: AsRef`). - // - // This is somewhat problematic, as the current scheme can't really - // handle it turning to be a projection. This does end up as truly - // ambiguous in most cases anyway. - // - // Take the fast path out - this also improves - // performance by preventing assemble_candidates_from_impls from - // matching every impl for this trait. - return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true }); - } - - let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; - - self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?; - - // Other bounds. Consider both in-scope bounds from fn decl - // and applicable impls. There is a certain set of precedence rules here. - let def_id = obligation.predicate.def_id(); - let lang_items = self.tcx().lang_items(); - - if lang_items.copy_trait() == Some(def_id) { - debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty()); - - // User-defined copy impls are permitted, but only for - // structs and enums. - self.assemble_candidates_from_impls(obligation, &mut candidates)?; - - // For other types, we'll use the builtin rules. - let copy_conditions = self.copy_clone_conditions(obligation); - self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?; - } else if lang_items.sized_trait() == Some(def_id) { - // Sized is never implementable by end-users, it is - // always automatically computed. - let sized_conditions = self.sized_conditions(obligation); - self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?; - } else if lang_items.unsize_trait() == Some(def_id) { - self.assemble_candidates_for_unsizing(obligation, &mut candidates); - } else { - if lang_items.clone_trait() == Some(def_id) { - // Same builtin conditions as `Copy`, i.e., every type which has builtin support - // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone` - // types have builtin support for `Clone`. - let clone_conditions = self.copy_clone_conditions(obligation); - self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?; - } - - self.assemble_generator_candidates(obligation, &mut candidates)?; - self.assemble_closure_candidates(obligation, &mut candidates)?; - self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; - self.assemble_candidates_from_impls(obligation, &mut candidates)?; - self.assemble_candidates_from_object_ty(obligation, &mut candidates); - } - - self.assemble_candidates_from_projected_tys(obligation, &mut candidates); - self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; - // Auto implementations have lower priority, so we only - // consider triggering a default if there is no other impl that can apply. - if candidates.vec.is_empty() { - self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?; - } - debug!("candidate list size: {}", candidates.vec.len()); - Ok(candidates) - } - - fn assemble_candidates_from_projected_tys( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - debug!("assemble_candidates_for_projected_tys({:?})", obligation); - - // Before we go into the whole placeholder thing, just - // quickly check if the self-type is a projection at all. - match obligation.predicate.skip_binder().trait_ref.self_ty().kind { - ty::Projection(_) | ty::Opaque(..) => {} - ty::Infer(ty::TyVar(_)) => { - span_bug!( - obligation.cause.span, - "Self=_ should have been handled by assemble_candidates" - ); - } - _ => return, - } - - let result = self.infcx.probe(|snapshot| { - self.match_projection_obligation_against_definition_bounds(obligation, snapshot) - }); - - if result { - candidates.vec.push(ProjectionCandidate); - } - } - - fn match_projection_obligation_against_definition_bounds( - &mut self, - obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> bool { - let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); - let (placeholder_trait_predicate, placeholder_map) = - self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); - debug!( - "match_projection_obligation_against_definition_bounds: \ - placeholder_trait_predicate={:?}", - placeholder_trait_predicate, - ); - - let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), - _ => { - span_bug!( - obligation.cause.span, - "match_projection_obligation_against_definition_bounds() called \ - but self-ty is not a projection: {:?}", - placeholder_trait_predicate.trait_ref.self_ty() - ); - } - }; - debug!( - "match_projection_obligation_against_definition_bounds: \ - def_id={:?}, substs={:?}", - def_id, substs - ); - - let predicates_of = self.tcx().predicates_of(def_id); - let bounds = predicates_of.instantiate(self.tcx(), substs); - debug!( - "match_projection_obligation_against_definition_bounds: \ - bounds={:?}", - bounds - ); - - let elaborated_predicates = util::elaborate_predicates(self.tcx(), bounds.predicates); - let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| { - self.infcx.probe(|_| { - self.match_projection( - obligation, - bound.clone(), - placeholder_trait_predicate.trait_ref.clone(), - &placeholder_map, - snapshot, - ) - }) - }); - - debug!( - "match_projection_obligation_against_definition_bounds: \ - matching_bound={:?}", - matching_bound - ); - match matching_bound { - None => false, - Some(bound) => { - // Repeat the successful match, if any, this time outside of a probe. - let result = self.match_projection( - obligation, - bound, - placeholder_trait_predicate.trait_ref.clone(), - &placeholder_map, - snapshot, - ); - - assert!(result); - true - } - } - } - - fn match_projection( - &mut self, - obligation: &TraitObligation<'tcx>, - trait_bound: ty::PolyTraitRef<'tcx>, - placeholder_trait_ref: ty::TraitRef<'tcx>, - placeholder_map: &PlaceholderMap<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> bool { - debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars()); - self.infcx - .at(&obligation.cause, obligation.param_env) - .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) - .is_ok() - && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok() - } - - /// Given an obligation like ``, searches the obligations that the caller - /// supplied to find out whether it is listed among them. - /// - /// Never affects the inference environment. - fn assemble_candidates_from_caller_bounds<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation); - - let all_bounds = stack - .obligation - .param_env - .caller_bounds - .iter() - .filter_map(|o| o.to_opt_poly_trait_ref()); - - // Micro-optimization: filter out predicates relating to different traits. - let matching_bounds = - all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); - - // Keep only those bounds which may apply, and propagate overflow if it occurs. - let mut param_candidates = vec![]; - for bound in matching_bounds { - let wc = self.evaluate_where_clause(stack, bound.clone())?; - if wc.may_apply() { - param_candidates.push(ParamCandidate(bound)); - } - } - - candidates.vec.extend(param_candidates); - - Ok(()) - } - - fn evaluate_where_clause<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - where_clause_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result { - self.evaluation_probe(|this| { - match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { - Ok(obligations) => { - this.evaluate_predicates_recursively(stack.list(), obligations.into_iter()) - } - Err(()) => Ok(EvaluatedToErr), - } - }) - } - - fn assemble_generator_candidates( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) { - return Ok(()); - } - - // Okay to skip binder because the substs on generator types never - // touch bound regions, they just capture the in-scope - // type/region parameters. - let self_ty = *obligation.self_ty().skip_binder(); - match self_ty.kind { - ty::Generator(..) => { - debug!( - "assemble_generator_candidates: self_ty={:?} obligation={:?}", - self_ty, obligation - ); - - candidates.vec.push(GeneratorCandidate); - } - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_generator_candidates: ambiguous self-type"); - candidates.ambiguous = true; - } - _ => {} - } - - Ok(()) - } - - /// Checks for the artificial impl that the compiler will create for an obligation like `X : - /// FnMut<..>` where `X` is a closure type. - /// - /// Note: the type parameters on a closure candidate are modeled as *output* type - /// parameters and hence do not affect whether this trait is a match or not. They will be - /// unified during the confirmation step. - fn assemble_closure_candidates( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - let kind = match self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) { - Some(k) => k, - None => { - return Ok(()); - } - }; - - // Okay to skip binder because the substs on closure types never - // touch bound regions, they just capture the in-scope - // type/region parameters - match obligation.self_ty().skip_binder().kind { - ty::Closure(closure_def_id, closure_substs) => { - debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation); - match self.infcx.closure_kind(closure_def_id, closure_substs) { - Some(closure_kind) => { - debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); - if closure_kind.extends(kind) { - candidates.vec.push(ClosureCandidate); - } - } - None => { - debug!("assemble_unboxed_candidates: closure_kind not yet known"); - candidates.vec.push(ClosureCandidate); - } - } - } - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); - candidates.ambiguous = true; - } - _ => {} - } - - Ok(()) - } - - /// Implements one of the `Fn()` family for a fn pointer. - fn assemble_fn_pointer_candidates( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - // We provide impl of all fn traits for fn pointers. - if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() { - return Ok(()); - } - - // Okay to skip binder because what we are inspecting doesn't involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); - match self_ty.kind { - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_fn_pointer_candidates: ambiguous self-type"); - candidates.ambiguous = true; // Could wind up being a fn() type. - } - // Provide an impl, but only for suitable `fn` pointers. - ty::FnDef(..) | ty::FnPtr(_) => { - if let ty::FnSig { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - c_variadic: false, - .. - } = self_ty.fn_sig(self.tcx()).skip_binder() - { - candidates.vec.push(FnPointerCandidate); - } - } - _ => {} - } - - Ok(()) - } - - /// Searches for impls that might apply to `obligation`. - fn assemble_candidates_from_impls( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - debug!("assemble_candidates_from_impls(obligation={:?})", obligation); - - self.tcx().for_each_relevant_impl( - obligation.predicate.def_id(), - obligation.predicate.skip_binder().trait_ref.self_ty(), - |impl_def_id| { - self.infcx.probe(|snapshot| { - if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) { - candidates.vec.push(ImplCandidate(impl_def_id)); - } - }); - }, - ); - - Ok(()) - } - - fn assemble_candidates_from_auto_impls( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - // Okay to skip binder here because the tests we do below do not involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); - debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty); - - let def_id = obligation.predicate.def_id(); - - if self.tcx().trait_is_auto(def_id) { - match self_ty.kind { - ty::Dynamic(..) => { - // For object types, we don't know what the closed - // over types are. This means we conservatively - // say nothing; a candidate may be added by - // `assemble_candidates_from_object_ty`. - } - ty::Foreign(..) => { - // Since the contents of foreign types is unknown, - // we don't add any `..` impl. Default traits could - // still be provided by a manual implementation for - // this trait and type. - } - ty::Param(..) | ty::Projection(..) => { - // In these cases, we don't know what the actual - // type is. Therefore, we cannot break it down - // into its constituent types. So we don't - // consider the `..` impl but instead just add no - // candidates: this means that typeck will only - // succeed if there is another reason to believe - // that this obligation holds. That could be a - // where-clause or, in the case of an object type, - // it could be that the object type lists the - // trait (e.g., `Foo+Send : Send`). See - // `compile-fail/typeck-default-trait-impl-send-param.rs` - // for an example of a test case that exercises - // this path. - } - ty::Infer(ty::TyVar(_)) => { - // The auto impl might apply; we don't know. - candidates.ambiguous = true; - } - ty::Generator(_, _, movability) - if self.tcx().lang_items().unpin_trait() == Some(def_id) => - { - match movability { - hir::Movability::Static => { - // Immovable generators are never `Unpin`, so - // suppress the normal auto-impl candidate for it. - } - hir::Movability::Movable => { - // Movable generators are always `Unpin`, so add an - // unconditional builtin candidate. - candidates.vec.push(BuiltinCandidate { has_nested: false }); - } - } - } - - _ => candidates.vec.push(AutoImplCandidate(def_id)), - } - } - - Ok(()) - } - - /// Searches for impls that might apply to `obligation`. - fn assemble_candidates_from_object_ty( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - debug!( - "assemble_candidates_from_object_ty(self_ty={:?})", - obligation.self_ty().skip_binder() - ); - - self.infcx.probe(|_snapshot| { - // The code below doesn't care about regions, and the - // self-ty here doesn't escape this probe, so just erase - // any LBR. - let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty()); - let poly_trait_ref = match self_ty.kind { - ty::Dynamic(ref data, ..) => { - if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { - debug!( - "assemble_candidates_from_object_ty: matched builtin bound, \ - pushing candidate" - ); - candidates.vec.push(BuiltinObjectCandidate); - return; - } - - if let Some(principal) = data.principal() { - if !self.infcx.tcx.features().object_safe_for_dispatch { - principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().is_object_safe(principal.def_id()) { - principal.with_self_ty(self.tcx(), self_ty) - } else { - return; - } - } else { - // Only auto trait bounds exist. - return; - } - } - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_candidates_from_object_ty: ambiguous"); - candidates.ambiguous = true; // could wind up being an object type - return; - } - _ => return, - }; - - debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref); - - // Count only those upcast versions that match the trait-ref - // we are looking for. Specifically, do not only check for the - // correct trait, but also the correct type parameters. - // For example, we may be trying to upcast `Foo` to `Bar`, - // but `Foo` is declared as `trait Foo: Bar`. - let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref) - .filter(|upcast_trait_ref| { - self.infcx - .probe(|_| self.match_poly_trait_ref(obligation, *upcast_trait_ref).is_ok()) - }) - .count(); - - if upcast_trait_refs > 1 { - // Can be upcast in many ways; need more type information. - candidates.ambiguous = true; - } else if upcast_trait_refs == 1 { - candidates.vec.push(ObjectCandidate); - } - }) - } - - /// Searches for unsizing that might apply to `obligation`. - fn assemble_candidates_for_unsizing( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - // We currently never consider higher-ranked obligations e.g. - // `for<'a> &'a T: Unsize` to be implemented. This is not - // because they are a priori invalid, and we could potentially add support - // for them later, it's just that there isn't really a strong need for it. - // A `T: Unsize` obligation is always used as part of a `T: CoerceUnsize` - // impl, and those are generally applied to concrete types. - // - // That said, one might try to write a fn with a where clause like - // for<'a> Foo<'a, T>: Unsize> - // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`. - // Still, you'd be more likely to write that where clause as - // T: Trait - // so it seems ok if we (conservatively) fail to accept that `Unsize` - // obligation above. Should be possible to extend this in the future. - let source = match obligation.self_ty().no_bound_vars() { - Some(t) => t, - None => { - // Don't add any candidates if there are bound regions. - return; - } - }; - let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); - - debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); - - let may_apply = match (&source.kind, &target.kind) { - // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { - // Upcasts permit two things: - // - // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo` - // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b` - // - // Note that neither of these changes requires any - // change at runtime. Eventually this will be - // generalized. - // - // We always upcast when we can because of reason - // #2 (region bounds). - data_a.principal_def_id() == data_b.principal_def_id() - && data_b - .auto_traits() - // All of a's auto traits need to be in b's auto traits. - .all(|b| data_a.auto_traits().any(|a| a == b)) - } - - // `T` -> `Trait` - (_, &ty::Dynamic(..)) => true, - - // Ambiguous handling is below `T` -> `Trait`, because inference - // variables can still implement `Unsize` and nested - // obligations will have the final say (likely deferred). - (&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => { - debug!("assemble_candidates_for_unsizing: ambiguous"); - candidates.ambiguous = true; - false - } - - // `[T; n]` -> `[T]` - (&ty::Array(..), &ty::Slice(_)) => true, - - // `Struct` -> `Struct` - (&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => { - def_id_a == def_id_b - } - - // `(.., T)` -> `(.., U)` - (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(), - - _ => false, - }; - - if may_apply { - candidates.vec.push(BuiltinUnsizeCandidate); - } - } - - fn assemble_candidates_for_trait_alias( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - // Okay to skip binder here because the tests we do below do not involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); - debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty); - - let def_id = obligation.predicate.def_id(); - - if self.tcx().is_trait_alias(def_id) { - candidates.vec.push(TraitAliasCandidate(def_id)); - } - - Ok(()) - } - - /////////////////////////////////////////////////////////////////////////// - // WINNOW - // - // Winnowing is the process of attempting to resolve ambiguity by - // probing further. During the winnowing process, we unify all - // type variables and then we also attempt to evaluate recursive - // bounds to see if they are satisfied. - - /// Returns `true` if `victim` should be dropped in favor of - /// `other`. Generally speaking we will drop duplicate - /// candidates and prefer where-clause candidates. - /// - /// See the comment for "SelectionCandidate" for more details. - fn candidate_should_be_dropped_in_favor_of( - &mut self, - victim: &EvaluatedCandidate<'tcx>, - other: &EvaluatedCandidate<'tcx>, - needs_infer: bool, - ) -> bool { - if victim.candidate == other.candidate { - return true; - } - - // Check if a bound would previously have been removed when normalizing - // the param_env so that it can be given the lowest priority. See - // #50825 for the motivation for this. - let is_global = - |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions(); - - match other.candidate { - // Prefer `BuiltinCandidate { has_nested: false }` to anything else. - // This is a fix for #53123 and prevents winnowing from accidentally extending the - // lifetime of a variable. - BuiltinCandidate { has_nested: false } => true, - ParamCandidate(ref cand) => match victim.candidate { - AutoImplCandidate(..) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates" - ); - } - // Prefer `BuiltinCandidate { has_nested: false }` to anything else. - // This is a fix for #53123 and prevents winnowing from accidentally extending the - // lifetime of a variable. - BuiltinCandidate { has_nested: false } => false, - ImplCandidate(..) - | ClosureCandidate - | GeneratorCandidate - | FnPointerCandidate - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | BuiltinCandidate { .. } - | TraitAliasCandidate(..) => { - // Global bounds from the where clause should be ignored - // here (see issue #50825). Otherwise, we have a where - // clause so don't go around looking for impls. - !is_global(cand) - } - ObjectCandidate | ProjectionCandidate => { - // Arbitrarily give param candidates priority - // over projection and object candidates. - !is_global(cand) - } - ParamCandidate(..) => false, - }, - ObjectCandidate | ProjectionCandidate => match victim.candidate { - AutoImplCandidate(..) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates" - ); - } - // Prefer `BuiltinCandidate { has_nested: false }` to anything else. - // This is a fix for #53123 and prevents winnowing from accidentally extending the - // lifetime of a variable. - BuiltinCandidate { has_nested: false } => false, - ImplCandidate(..) - | ClosureCandidate - | GeneratorCandidate - | FnPointerCandidate - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | BuiltinCandidate { .. } - | TraitAliasCandidate(..) => true, - ObjectCandidate | ProjectionCandidate => { - // Arbitrarily give param candidates priority - // over projection and object candidates. - true - } - ParamCandidate(ref cand) => is_global(cand), - }, - ImplCandidate(other_def) => { - // See if we can toss out `victim` based on specialization. - // This requires us to know *for sure* that the `other` impl applies - // i.e., `EvaluatedToOk`. - if other.evaluation.must_apply_modulo_regions() { - match victim.candidate { - ImplCandidate(victim_def) => { - let tcx = self.tcx(); - if tcx.specializes((other_def, victim_def)) { - return true; - } - return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) { - Some(ty::ImplOverlapKind::Permitted { marker: true }) => { - // Subtle: If the predicate we are evaluating has inference - // variables, do *not* allow discarding candidates due to - // marker trait impls. - // - // Without this restriction, we could end up accidentally - // constrainting inference variables based on an arbitrarily - // chosen trait impl. - // - // Imagine we have the following code: - // - // ```rust - // #[marker] trait MyTrait {} - // impl MyTrait for u8 {} - // impl MyTrait for bool {} - // ``` - // - // And we are evaluating the predicate `<_#0t as MyTrait>`. - // - // During selection, we will end up with one candidate for each - // impl of `MyTrait`. If we were to discard one impl in favor - // of the other, we would be left with one candidate, causing - // us to "successfully" select the predicate, unifying - // _#0t with (for example) `u8`. - // - // However, we have no reason to believe that this unification - // is correct - we've essentially just picked an arbitrary - // *possibility* for _#0t, and required that this be the *only* - // possibility. - // - // Eventually, we will either: - // 1) Unify all inference variables in the predicate through - // some other means (e.g. type-checking of a function). We will - // then be in a position to drop marker trait candidates - // without constraining inference variables (since there are - // none left to constrin) - // 2) Be left with some unconstrained inference variables. We - // will then correctly report an inference error, since the - // existence of multiple marker trait impls tells us nothing - // about which one should actually apply. - !needs_infer - } - Some(_) => true, - None => false, - }; - } - ParamCandidate(ref cand) => { - // Prefer the impl to a global where clause candidate. - return is_global(cand); - } - _ => (), - } - } - - false - } - ClosureCandidate - | GeneratorCandidate - | FnPointerCandidate - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | BuiltinCandidate { has_nested: true } => { - match victim.candidate { - ParamCandidate(ref cand) => { - // Prefer these to a global where-clause bound - // (see issue #50825). - is_global(cand) && other.evaluation.must_apply_modulo_regions() - } - _ => false, - } - } - _ => false, - } - } - - /////////////////////////////////////////////////////////////////////////// - // BUILTIN BOUNDS - // - // These cover the traits that are built-in to the language - // itself: `Copy`, `Clone` and `Sized`. - - fn assemble_builtin_bound_candidates( - &mut self, - conditions: BuiltinImplConditions<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - match conditions { - BuiltinImplConditions::Where(nested) => { - debug!("builtin_bound: nested={:?}", nested); - candidates - .vec - .push(BuiltinCandidate { has_nested: nested.skip_binder().len() > 0 }); - } - BuiltinImplConditions::None => {} - BuiltinImplConditions::Ambiguous => { - debug!("assemble_builtin_bound_candidates: ambiguous builtin"); - candidates.ambiguous = true; - } - } - - Ok(()) - } - - fn sized_conditions( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> BuiltinImplConditions<'tcx> { - use self::BuiltinImplConditions::{Ambiguous, None, Where}; - - // NOTE: binder moved to (*) - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - - match self_ty.kind { - ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::RawPtr(..) - | ty::Char - | ty::Ref(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Array(..) - | ty::Closure(..) - | ty::Never - | ty::Error => { - // safe for everything - Where(ty::Binder::dummy(Vec::new())) - } - - ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None, - - ty::Tuple(tys) => { - Where(ty::Binder::bind(tys.last().into_iter().map(|k| k.expect_ty()).collect())) - } - - ty::Adt(def, substs) => { - let sized_crit = def.sized_constraint(self.tcx()); - // (*) binder moved here - Where(ty::Binder::bind( - sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect(), - )) - } - - ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None, - ty::Infer(ty::TyVar(_)) => Ambiguous, - - ty::UnnormalizedProjection(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => { - bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); - } - } - } - - fn copy_clone_conditions( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> BuiltinImplConditions<'tcx> { - // NOTE: binder moved to (*) - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - - use self::BuiltinImplConditions::{Ambiguous, None, Where}; - - match self_ty.kind { - ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Error => Where(ty::Binder::dummy(Vec::new())), - - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::Char - | ty::RawPtr(..) - | ty::Never - | ty::Ref(_, _, hir::Mutability::Not) => { - // Implementations provided in libcore - None - } - - ty::Dynamic(..) - | ty::Str - | ty::Slice(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Foreign(..) - | ty::Ref(_, _, hir::Mutability::Mut) => None, - - ty::Array(element_ty, _) => { - // (*) binder moved here - Where(ty::Binder::bind(vec![element_ty])) - } - - ty::Tuple(tys) => { - // (*) binder moved here - Where(ty::Binder::bind(tys.iter().map(|k| k.expect_ty()).collect())) - } - - ty::Closure(def_id, substs) => { - // (*) binder moved here - Where(ty::Binder::bind(substs.as_closure().upvar_tys(def_id, self.tcx()).collect())) - } - - ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => { - // Fallback to whatever user-defined impls exist in this case. - None - } - - ty::Infer(ty::TyVar(_)) => { - // Unbound type variable. Might or might not have - // applicable impls and so forth, depending on what - // those type variables wind up being bound to. - Ambiguous - } - - ty::UnnormalizedProjection(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => { - bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); - } - } - } - - /// For default impls, we need to break apart a type into its - /// "constituent types" -- meaning, the types that it contains. - /// - /// Here are some (simple) examples: - /// - /// ``` - /// (i32, u32) -> [i32, u32] - /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32] - /// Bar where struct Bar { x: T, y: u32 } -> [i32, u32] - /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] - /// ``` - fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { - match t.kind { - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Str - | ty::Error - | ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::Never - | ty::Char => Vec::new(), - - ty::UnnormalizedProjection(..) - | ty::Placeholder(..) - | ty::Dynamic(..) - | ty::Param(..) - | ty::Foreign(..) - | ty::Projection(..) - | ty::Bound(..) - | ty::Infer(ty::TyVar(_)) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => { - bug!("asked to assemble constituent types of unexpected type: {:?}", t); - } - - ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { - vec![element_ty] - } - - ty::Array(element_ty, _) | ty::Slice(element_ty) => vec![element_ty], - - ty::Tuple(ref tys) => { - // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - tys.iter().map(|k| k.expect_ty()).collect() - } - - ty::Closure(def_id, ref substs) => { - substs.as_closure().upvar_tys(def_id, self.tcx()).collect() - } - - ty::Generator(def_id, ref substs, _) => { - let witness = substs.as_generator().witness(def_id, self.tcx()); - substs - .as_generator() - .upvar_tys(def_id, self.tcx()) - .chain(iter::once(witness)) - .collect() - } - - ty::GeneratorWitness(types) => { - // This is sound because no regions in the witness can refer to - // the binder outside the witness. So we'll effectivly reuse - // the implicit binder around the witness. - types.skip_binder().to_vec() - } - - // For `PhantomData`, we pass `T`. - ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(), - - ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect(), - - ty::Opaque(def_id, substs) => { - // We can resolve the `impl Trait` to its concrete type, - // which enforces a DAG between the functions requiring - // the auto trait bounds in question. - vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)] - } - } - } - - fn collect_predicates_for_types( - &mut self, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - recursion_depth: usize, - trait_def_id: DefId, - types: ty::Binder>>, - ) -> Vec> { - // Because the types were potentially derived from - // higher-ranked obligations they may reference late-bound - // regions. For example, `for<'a> Foo<&'a int> : Copy` would - // yield a type like `for<'a> &'a int`. In general, we - // maintain the invariant that we never manipulate bound - // regions, so we have to process these bound regions somehow. - // - // The strategy is to: - // - // 1. Instantiate those regions to placeholder regions (e.g., - // `for<'a> &'a int` becomes `&0 int`. - // 2. Produce something like `&'0 int : Copy` - // 3. Re-bind the regions back to `for<'a> &'a int : Copy` - - types - .skip_binder() - .into_iter() - .flat_map(|ty| { - // binder moved -\ - let ty: ty::Binder> = ty::Binder::bind(ty); // <----/ - - self.infcx.commit_unconditionally(|_| { - let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty); - let Normalized { value: normalized_ty, mut obligations } = - project::normalize_with_depth( - self, - param_env, - cause.clone(), - recursion_depth, - &skol_ty, - ); - let skol_obligation = predicate_for_trait_def( - self.tcx(), - param_env, - cause.clone(), - trait_def_id, - recursion_depth, - normalized_ty, - &[], - ); - obligations.push(skol_obligation); - obligations - }) - }) - .collect() - } - - /////////////////////////////////////////////////////////////////////////// - // CONFIRMATION - // - // Confirmation unifies the output type parameters of the trait - // with the values found in the obligation, possibly yielding a - // type error. See the [rustc guide] for more details. - // - // [rustc guide]: - // https://rust-lang.github.io/rustc-guide/traits/resolution.html#confirmation - - fn confirm_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - candidate: SelectionCandidate<'tcx>, - ) -> Result, SelectionError<'tcx>> { - debug!("confirm_candidate({:?}, {:?})", obligation, candidate); - - match candidate { - BuiltinCandidate { has_nested } => { - let data = self.confirm_builtin_candidate(obligation, has_nested); - Ok(VtableBuiltin(data)) - } - - ParamCandidate(param) => { - let obligations = self.confirm_param_candidate(obligation, param); - Ok(VtableParam(obligations)) - } - - ImplCandidate(impl_def_id) => { - Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id))) - } - - AutoImplCandidate(trait_def_id) => { - let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); - Ok(VtableAutoImpl(data)) - } - - ProjectionCandidate => { - self.confirm_projection_candidate(obligation); - Ok(VtableParam(Vec::new())) - } - - ClosureCandidate => { - let vtable_closure = self.confirm_closure_candidate(obligation)?; - Ok(VtableClosure(vtable_closure)) - } - - GeneratorCandidate => { - let vtable_generator = self.confirm_generator_candidate(obligation)?; - Ok(VtableGenerator(vtable_generator)) - } - - FnPointerCandidate => { - let data = self.confirm_fn_pointer_candidate(obligation)?; - Ok(VtableFnPointer(data)) - } - - TraitAliasCandidate(alias_def_id) => { - let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); - Ok(VtableTraitAlias(data)) - } - - ObjectCandidate => { - let data = self.confirm_object_candidate(obligation); - Ok(VtableObject(data)) - } - - BuiltinObjectCandidate => { - // This indicates something like `Trait + Send: Send`. In this case, we know that - // this holds because that's what the object type is telling us, and there's really - // no additional obligations to prove and no types in particular to unify, etc. - Ok(VtableParam(Vec::new())) - } - - BuiltinUnsizeCandidate => { - let data = self.confirm_builtin_unsize_candidate(obligation)?; - Ok(VtableBuiltin(data)) - } - } - } - - fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { - self.infcx.commit_unconditionally(|snapshot| { - let result = - self.match_projection_obligation_against_definition_bounds(obligation, snapshot); - assert!(result); - }) - } - - fn confirm_param_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - param: ty::PolyTraitRef<'tcx>, - ) -> Vec> { - debug!("confirm_param_candidate({:?},{:?})", obligation, param); - - // During evaluation, we already checked that this - // where-clause trait-ref could be unified with the obligation - // trait-ref. Repeat that unification now without any - // transactional boundary; it should not fail. - match self.match_where_clause_trait_ref(obligation, param.clone()) { - Ok(obligations) => obligations, - Err(()) => { - bug!( - "Where clause `{:?}` was applicable to `{:?}` but now is not", - param, - obligation - ); - } - } - } - - fn confirm_builtin_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - has_nested: bool, - ) -> VtableBuiltinData> { - debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested); - - let lang_items = self.tcx().lang_items(); - let obligations = if has_nested { - let trait_def = obligation.predicate.def_id(); - let conditions = if Some(trait_def) == lang_items.sized_trait() { - self.sized_conditions(obligation) - } else if Some(trait_def) == lang_items.copy_trait() { - self.copy_clone_conditions(obligation) - } else if Some(trait_def) == lang_items.clone_trait() { - self.copy_clone_conditions(obligation) - } else { - bug!("unexpected builtin trait {:?}", trait_def) - }; - let nested = match conditions { - BuiltinImplConditions::Where(nested) => nested, - _ => bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation), - }; - - let cause = obligation.derived_cause(BuiltinDerivedObligation); - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def, - nested, - ) - } else { - vec![] - }; - - debug!("confirm_builtin_candidate: obligations={:?}", obligations); - - VtableBuiltinData { nested: obligations } - } - - /// This handles the case where a `auto trait Foo` impl is being used. - /// The idea is that the impl applies to `X : Foo` if the following conditions are met: - /// - /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds - /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. - fn confirm_auto_impl_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId, - ) -> VtableAutoImplData> { - debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id); - - let types = obligation.predicate.map_bound(|inner| { - let self_ty = self.infcx.shallow_resolve(inner.self_ty()); - self.constituent_types_for_ty(self_ty) - }); - self.vtable_auto_impl(obligation, trait_def_id, types) - } - - /// See `confirm_auto_impl_candidate`. - fn vtable_auto_impl( - &mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId, - nested: ty::Binder>>, - ) -> VtableAutoImplData> { - debug!("vtable_auto_impl: nested={:?}", nested); - - let cause = obligation.derived_cause(BuiltinDerivedObligation); - let mut obligations = self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def_id, - nested, - ); - - let trait_obligations: Vec> = - self.infcx.commit_unconditionally(|_| { - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, _) = - self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref); - let cause = obligation.derived_cause(ImplDerivedObligation); - self.impl_or_trait_obligations( - cause, - obligation.recursion_depth + 1, - obligation.param_env, - trait_def_id, - &trait_ref.substs, - ) - }); - - // Adds the predicates from the trait. Note that this contains a `Self: Trait` - // predicate as usual. It won't have any effect since auto traits are coinductive. - obligations.extend(trait_obligations); - - debug!("vtable_auto_impl: obligations={:?}", obligations); - - VtableAutoImplData { trait_def_id, nested: obligations } - } - - fn confirm_impl_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - impl_def_id: DefId, - ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id); - - // First, create the substitutions by matching the impl again, - // this time not in a probe. - self.infcx.commit_unconditionally(|snapshot| { - let substs = self.rematch_impl(impl_def_id, obligation, snapshot); - debug!("confirm_impl_candidate: substs={:?}", substs); - let cause = obligation.derived_cause(ImplDerivedObligation); - self.vtable_impl( - impl_def_id, - substs, - cause, - obligation.recursion_depth + 1, - obligation.param_env, - ) - }) - } - - fn vtable_impl( - &mut self, - impl_def_id: DefId, - mut substs: Normalized<'tcx, SubstsRef<'tcx>>, - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { - debug!( - "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})", - impl_def_id, substs, recursion_depth, - ); - - let mut impl_obligations = self.impl_or_trait_obligations( - cause, - recursion_depth, - param_env, - impl_def_id, - &substs.value, - ); - - debug!( - "vtable_impl: impl_def_id={:?} impl_obligations={:?}", - impl_def_id, impl_obligations - ); - - // Because of RFC447, the impl-trait-ref and obligations - // are sufficient to determine the impl substs, without - // relying on projections in the impl-trait-ref. - // - // e.g., `impl> Foo<::T> for V` - impl_obligations.append(&mut substs.obligations); - - VtableImplData { impl_def_id, substs: substs.value, nested: impl_obligations } - } - - fn confirm_object_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> VtableObjectData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_object_candidate({:?})", obligation); - - // FIXME(nmatsakis) skipping binder here seems wrong -- we should - // probably flatten the binder from the obligation and the binder - // from the object. Have to try to make a broken test case that - // results. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let poly_trait_ref = match self_ty.kind { - ty::Dynamic(ref data, ..) => data - .principal() - .unwrap_or_else(|| { - span_bug!(obligation.cause.span, "object candidate with no principal") - }) - .with_self_ty(self.tcx(), self_ty), - _ => span_bug!(obligation.cause.span, "object candidate with non-object"), - }; - - let mut upcast_trait_ref = None; - let mut nested = vec![]; - let vtable_base; - - { - let tcx = self.tcx(); - - // We want to find the first supertrait in the list of - // supertraits that we can unify with, and do that - // unification. We know that there is exactly one in the list - // where we can unify, because otherwise select would have - // reported an ambiguity. (When we do find a match, also - // record it for later.) - let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(|&t| { - match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) { - Ok(obligations) => { - upcast_trait_ref = Some(t); - nested.extend(obligations); - false - } - Err(_) => true, - } - }); - - // Additionally, for each of the non-matching predicates that - // we pass over, we sum up the set of number of vtable - // entries, so that we can compute the offset for the selected - // trait. - vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum(); - } - - VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested } - } - - fn confirm_fn_pointer_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result>, SelectionError<'tcx>> { - debug!("confirm_fn_pointer_candidate({:?})", obligation); - - // Okay to skip binder; it is reintroduced below. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let sig = self_ty.fn_sig(self.tcx()); - let trait_ref = closure_trait_ref_and_return_type( - self.tcx(), - obligation.predicate.def_id(), - self_ty, - sig, - util::TupleArgumentsFlag::Yes, - ) - .map_bound(|(trait_ref, _)| trait_ref); - - let Normalized { value: trait_ref, obligations } = project::normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); - - self.confirm_poly_trait_refs( - obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref, - )?; - Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations }) - } - - fn confirm_trait_alias_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - alias_def_id: DefId, - ) -> VtableTraitAliasData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id); - - self.infcx.commit_unconditionally(|_| { - let (predicate, _) = - self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); - let trait_ref = predicate.trait_ref; - let trait_def_id = trait_ref.def_id; - let substs = trait_ref.substs; - - let trait_obligations = self.impl_or_trait_obligations( - obligation.cause.clone(), - obligation.recursion_depth, - obligation.param_env, - trait_def_id, - &substs, - ); - - debug!( - "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}", - trait_def_id, trait_obligations - ); - - VtableTraitAliasData { alias_def_id, substs: substs, nested: trait_obligations } - }) - } +//! Candidate selection. See the [rustc dev guide] for more information on how this works. +//! +//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection - fn confirm_generator_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result>, SelectionError<'tcx>> { - // Okay to skip binder because the substs on generator types never - // touch bound regions, they just capture the in-scope - // type/region parameters. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let (generator_def_id, substs) = match self_ty.kind { - ty::Generator(id, substs, _) => (id, substs), - _ => bug!("closure candidate for non-closure {:?}", obligation), - }; +use self::EvaluationResult::*; - debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs); +use super::{SelectionError, SelectionResult}; - let trait_ref = self.generator_trait_ref_unnormalized(obligation, generator_def_id, substs); - let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); +use crate::dep_graph::DepNodeIndex; +use crate::ty::{self, TyCtxt}; - debug!( - "confirm_generator_candidate(generator_def_id={:?}, \ - trait_ref={:?}, obligations={:?})", - generator_def_id, trait_ref, obligations - ); +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Lock; +use rustc_hir::def_id::DefId; - obligations.extend(self.confirm_poly_trait_refs( - obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref, - )?); +#[derive(Clone, Default)] +pub struct SelectionCache<'tcx> { + pub hashmap: Lock< + FxHashMap< + ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>, + WithDepNode>>, + >, + >, +} - Ok(VtableGeneratorData { generator_def_id, substs, nested: obligations }) +impl<'tcx> SelectionCache<'tcx> { + /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear` + pub fn clear(&self) { + *self.hashmap.borrow_mut() = Default::default(); } +} - fn confirm_closure_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result>, SelectionError<'tcx>> { - debug!("confirm_closure_candidate({:?})", obligation); +/// The selection process begins by considering all impls, where +/// clauses, and so forth that might resolve an obligation. Sometimes +/// we'll be able to say definitively that (e.g.) an impl does not +/// apply to the obligation: perhaps it is defined for `usize` but the +/// obligation is for `int`. In that case, we drop the impl out of the +/// list. But the other cases are considered *candidates*. +/// +/// For selection to succeed, there must be exactly one matching +/// candidate. If the obligation is fully known, this is guaranteed +/// by coherence. However, if the obligation contains type parameters +/// or variables, there may be multiple such impls. +/// +/// It is not a real problem if multiple matching impls exist because +/// of type variables - it just means the obligation isn't sufficiently +/// elaborated. In that case we report an ambiguity, and the caller can +/// try again after more type information has been gathered or report a +/// "type annotations needed" error. +/// +/// However, with type parameters, this can be a real problem - type +/// parameters don't unify with regular types, but they *can* unify +/// with variables from blanket impls, and (unless we know its bounds +/// will always be satisfied) picking the blanket impl will be wrong +/// for at least *some* substitutions. To make this concrete, if we have +/// +/// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; } +/// impl AsDebug for T { +/// type Out = T; +/// fn debug(self) -> fmt::Debug { self } +/// } +/// fn foo(t: T) { println!("{:?}", ::debug(t)); } +/// +/// we can't just use the impl to resolve the `` obligation +/// -- a type from another crate (that doesn't implement `fmt::Debug`) could +/// implement `AsDebug`. +/// +/// Because where-clauses match the type exactly, multiple clauses can +/// only match if there are unresolved variables, and we can mostly just +/// report this ambiguity in that case. This is still a problem - we can't +/// *do anything* with ambiguities that involve only regions. This is issue +/// #21974. +/// +/// If a single where-clause matches and there are no inference +/// variables left, then it definitely matches and we can just select +/// it. +/// +/// In fact, we even select the where-clause when the obligation contains +/// inference variables. The can lead to inference making "leaps of logic", +/// for example in this situation: +/// +/// pub trait Foo { fn foo(&self) -> T; } +/// impl Foo<()> for T { fn foo(&self) { } } +/// impl Foo for bool { fn foo(&self) -> bool { *self } } +/// +/// pub fn foo(t: T) where T: Foo { +/// println!("{:?}", >::foo(&t)); +/// } +/// fn main() { foo(false); } +/// +/// Here the obligation `>` can be matched by both the blanket +/// impl and the where-clause. We select the where-clause and unify `$0=bool`, +/// so the program prints "false". However, if the where-clause is omitted, +/// the blanket impl is selected, we unify `$0=()`, and the program prints +/// "()". +/// +/// Exactly the same issues apply to projection and object candidates, except +/// that we can have both a projection candidate and a where-clause candidate +/// for the same obligation. In that case either would do (except that +/// different "leaps of logic" would occur if inference variables are +/// present), and we just pick the where-clause. This is, for example, +/// required for associated types to work in default impls, as the bounds +/// are visible both as projection bounds and as where-clauses from the +/// parameter environment. +#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)] +pub enum SelectionCandidate<'tcx> { + BuiltinCandidate { + /// `false` if there are no *further* obligations. + has_nested: bool, + }, + ParamCandidate(ty::PolyTraitRef<'tcx>), + ImplCandidate(DefId), + AutoImplCandidate(DefId), - let kind = self - .tcx() - .fn_trait_kind_from_lang_item(obligation.predicate.def_id()) - .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation)); + /// This is a trait matching with a projected type as `Self`, and + /// we found an applicable bound in the trait definition. + ProjectionCandidate, - // Okay to skip binder because the substs on closure types never - // touch bound regions, they just capture the in-scope - // type/region parameters. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let (closure_def_id, substs) = match self_ty.kind { - ty::Closure(id, substs) => (id, substs), - _ => bug!("closure candidate for non-closure {:?}", obligation), - }; + /// Implementation of a `Fn`-family trait by one of the anonymous types + /// generated for a `||` expression. + ClosureCandidate, - let trait_ref = self.closure_trait_ref_unnormalized(obligation, closure_def_id, substs); - let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); + /// Implementation of a `Generator` trait by one of the anonymous types + /// generated for a generator. + GeneratorCandidate, - debug!( - "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", - closure_def_id, trait_ref, obligations - ); + /// Implementation of a `Fn`-family trait by one of the anonymous + /// types generated for a fn pointer type (e.g., `fn(int) -> int`) + FnPointerCandidate, - obligations.extend(self.confirm_poly_trait_refs( - obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref, - )?); + TraitAliasCandidate(DefId), - // FIXME: Chalk + ObjectCandidate, - if !self.tcx().sess.opts.debugging_opts.chalk { - obligations.push(Obligation::new( - obligation.cause.clone(), - obligation.param_env, - ty::Predicate::ClosureKind(closure_def_id, substs, kind), - )); - } + BuiltinObjectCandidate, - Ok(VtableClosureData { closure_def_id, substs: substs, nested: obligations }) - } + BuiltinUnsizeCandidate, +} - /// In the case of closure types and fn pointers, - /// we currently treat the input type parameters on the trait as - /// outputs. This means that when we have a match we have only - /// considered the self type, so we have to go back and make sure - /// to relate the argument types too. This is kind of wrong, but - /// since we control the full set of impls, also not that wrong, - /// and it DOES yield better error messages (since we don't report - /// errors as if there is no applicable impl, but rather report - /// errors are about mismatched argument types. +/// The result of trait evaluation. The order is important +/// here as the evaluation of a list is the maximum of the +/// evaluations. +/// +/// The evaluation results are ordered: +/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions` +/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown` +/// - `EvaluatedToErr` implies `EvaluatedToRecur` +/// - the "union" of evaluation results is equal to their maximum - +/// all the "potential success" candidates can potentially succeed, +/// so they are noops when unioned with a definite error, and within +/// the categories it's easy to see that the unions are correct. +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)] +pub enum EvaluationResult { + /// Evaluation successful. + EvaluatedToOk, + /// Evaluation successful, but there were unevaluated region obligations. + EvaluatedToOkModuloRegions, + /// Evaluation is known to be ambiguous -- it *might* hold for some + /// assignment of inference variables, but it might not. /// - /// Here is an example. Imagine we have a closure expression - /// and we desugared it so that the type of the expression is - /// `Closure`, and `Closure` expects an int as argument. Then it - /// is "as if" the compiler generated this impl: + /// While this has the same meaning as `EvaluatedToUnknown` -- we can't + /// know whether this obligation holds or not -- it is the result we + /// would get with an empty stack, and therefore is cacheable. + EvaluatedToAmbig, + /// Evaluation failed because of recursion involving inference + /// variables. We are somewhat imprecise there, so we don't actually + /// know the real result. /// - /// impl Fn(int) for Closure { ... } + /// This can't be trivially cached for the same reason as `EvaluatedToRecur`. + EvaluatedToUnknown, + /// Evaluation failed because we encountered an obligation we are already + /// trying to prove on this branch. /// - /// Now imagine our obligation is `Fn(usize) for Closure`. So far - /// we have matched the self type `Closure`. At this point we'll - /// compare the `int` to `usize` and generate an error. + /// We know this branch can't be a part of a minimal proof-tree for + /// the "root" of our cycle, because then we could cut out the recursion + /// and maintain a valid proof tree. However, this does not mean + /// that all the obligations on this branch do not hold -- it's possible + /// that we entered this branch "speculatively", and that there + /// might be some other way to prove this obligation that does not + /// go through this cycle -- so we can't cache this as a failure. /// - /// Note that this checking occurs *after* the impl has selected, - /// because these output type parameters should not affect the - /// selection of the impl. Therefore, if there is a mismatch, we - /// report an error to the user. - fn confirm_poly_trait_refs( - &mut self, - obligation_cause: ObligationCause<'tcx>, - obligation_param_env: ty::ParamEnv<'tcx>, - obligation_trait_ref: ty::PolyTraitRef<'tcx>, - expected_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result>, SelectionError<'tcx>> { - self.infcx - .at(&obligation_cause, obligation_param_env) - .sup(obligation_trait_ref, expected_trait_ref) - .map(|InferOk { obligations, .. }| obligations) - .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) - } - - fn confirm_builtin_unsize_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result>, SelectionError<'tcx>> { - let tcx = self.tcx(); - - // `assemble_candidates_for_unsizing` should ensure there are no late-bound - // regions here. See the comment there for more details. - let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); - let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); - let target = self.infcx.shallow_resolve(target); - - debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target); - - let mut nested = vec![]; - match (&source.kind, &target.kind) { - // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { - // See `assemble_candidates_for_unsizing` for more info. - let existential_predicates = data_a.map_bound(|data_a| { - let iter = data_a - .principal() - .map(|x| ty::ExistentialPredicate::Trait(x)) - .into_iter() - .chain( - data_a - .projection_bounds() - .map(|x| ty::ExistentialPredicate::Projection(x)), - ) - .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait)); - tcx.mk_existential_predicates(iter) - }); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b); - - // Require that the traits involved in this upcast are **equal**; - // only the **lifetime bound** is changed. - // - // FIXME: This condition is arguably too strong -- it would - // suffice for the source trait to be a *subtype* of the target - // trait. In particular, changing from something like - // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be - // permitted. And, indeed, in the in commit - // 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this - // condition was loosened. However, when the leak check was - // added back, using subtype here actually guides the coercion - // code in such a way that it accepts `old-lub-glb-object.rs`. - // This is probably a good thing, but I've modified this to `.eq` - // because I want to continue rejecting that test (as we have - // done for quite some time) before we are firmly comfortable - // with what our behavior should be there. -nikomatsakis - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(target, source_trait) // FIXME -- see below - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - - // Register one obligation for 'a: 'b. - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(target), - ); - let outlives = ty::OutlivesPredicate(r_a, r_b); - nested.push(Obligation::with_depth( - cause, - obligation.recursion_depth + 1, - obligation.param_env, - ty::Binder::bind(outlives).to_predicate(), - )); - } - - // `T` -> `Trait` - (_, &ty::Dynamic(ref data, r)) => { - let mut object_dids = data.auto_traits().chain(data.principal_def_id()); - if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { - return Err(TraitNotObjectSafe(did)); - } - - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(target), - ); - - let predicate_to_obligation = |predicate| { - Obligation::with_depth( - cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - predicate, - ) - }; - - // Create obligations: - // - Casting `T` to `Trait` - // - For all the various builtin bounds attached to the object cast. (In other - // words, if the object type is `Foo + Send`, this would create an obligation for - // the `Send` check.) - // - Projection predicates - nested.extend( - data.iter().map(|predicate| { - predicate_to_obligation(predicate.with_self_ty(tcx, source)) - }), - ); - - // We can only make objects from sized types. - let tr = ty::TraitRef::new( - tcx.require_lang_item(lang_items::SizedTraitLangItem, None), - tcx.mk_substs_trait(source, &[]), - ); - nested.push(predicate_to_obligation(tr.without_const().to_predicate())); - - // If the type is `Foo + 'a`, ensure that the type - // being cast to `Foo + 'a` outlives `'a`: - let outlives = ty::OutlivesPredicate(source, r); - nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate())); - } - - // `[T; n]` -> `[T]` - (&ty::Array(a, _), &ty::Slice(b)) => { - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(b, a) - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - } - - // `Struct` -> `Struct` - (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { - let fields = - def.all_fields().map(|field| tcx.type_of(field.did)).collect::>(); - - // The last field of the structure has to exist and contain type parameters. - let field = if let Some(&field) = fields.last() { - field - } else { - return Err(Unimplemented); - }; - let mut ty_params = GrowableBitSet::new_empty(); - let mut found = false; - for ty in field.walk() { - if let ty::Param(p) = ty.kind { - ty_params.insert(p.index as usize); - found = true; - } - } - if !found { - return Err(Unimplemented); - } - - // Replace type parameters used in unsizing with - // Error and ensure they do not affect any other fields. - // This could be checked after type collection for any struct - // with a potentially unsized trailing field. - let params = substs_a - .iter() - .enumerate() - .map(|(i, &k)| if ty_params.contains(i) { tcx.types.err.into() } else { k }); - let substs = tcx.mk_substs(params); - for &ty in fields.split_last().unwrap().1 { - if ty.subst(tcx, substs).references_error() { - return Err(Unimplemented); - } - } - - // Extract `Field` and `Field` from `Struct` and `Struct`. - let inner_source = field.subst(tcx, substs_a); - let inner_target = field.subst(tcx, substs_b); - - // Check that the source struct with the target's - // unsized parameters is equal to the target. - let params = substs_a.iter().enumerate().map(|(i, &k)| { - if ty_params.contains(i) { substs_b.type_at(i).into() } else { k } - }); - let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(target, new_struct) - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - - // Construct the nested `Field: Unsize>` predicate. - nested.push(predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - inner_source, - &[inner_target.into()], - )); - } - - // `(.., T)` -> `(.., U)` - (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => { - assert_eq!(tys_a.len(), tys_b.len()); - - // The last field of the tuple has to exist. - let (&a_last, a_mid) = if let Some(x) = tys_a.split_last() { - x - } else { - return Err(Unimplemented); - }; - let &b_last = tys_b.last().unwrap(); - - // Check that the source tuple with the target's - // last element is equal to the target. - let new_tuple = tcx.mk_tup( - a_mid.iter().map(|k| k.expect_ty()).chain(iter::once(b_last.expect_ty())), - ); - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(target, new_tuple) - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - - // Construct the nested `T: Unsize` predicate. - nested.push(predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - a_last.expect_ty(), - &[b_last.into()], - )); - } - - _ => bug!(), - }; - - Ok(VtableBuiltinData { nested }) - } - - /////////////////////////////////////////////////////////////////////////// - // Matching + /// For example, suppose we have this: + /// + /// ```rust,ignore (pseudo-Rust) + /// pub trait Trait { fn xyz(); } + /// // This impl is "useless", but we can still have + /// // an `impl Trait for SomeUnsizedType` somewhere. + /// impl Trait for T { fn xyz() {} } + /// + /// pub fn foo() { + /// ::xyz(); + /// } + /// ``` + /// + /// When checking `foo`, we have to prove `T: Trait`. This basically + /// translates into this: + /// + /// ```plain,ignore + /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait + /// ``` + /// + /// When we try to prove it, we first go the first option, which + /// recurses. This shows us that the impl is "useless" -- it won't + /// tell us that `T: Trait` unless it already implemented `Trait` + /// by some other means. However, that does not prevent `T: Trait` + /// does not hold, because of the bound (which can indeed be satisfied + /// by `SomeUnsizedType` from another crate). // - // Matching is a common path used for both evaluation and - // confirmation. It basically unifies types that appear in impls - // and traits. This does affect the surrounding environment; - // therefore, when used during evaluation, match routines must be - // run inside of a `probe()` so that their side-effects are - // contained. - - fn rematch_impl( - &mut self, - impl_def_id: DefId, - obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> Normalized<'tcx, SubstsRef<'tcx>> { - match self.match_impl(impl_def_id, obligation, snapshot) { - Ok(substs) => substs, - Err(()) => { - bug!( - "Impl {:?} was matchable against {:?} but now is not", - impl_def_id, - obligation - ); - } - } - } - - fn match_impl( - &mut self, - impl_def_id: DefId, - obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> Result>, ()> { - let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - - // Before we create the substitutions and everything, first - // consider a "quick reject". This avoids creating more types - // and so forth that we need to. - if self.fast_reject_trait_refs(obligation, &impl_trait_ref) { - return Err(()); - } - - let (skol_obligation, placeholder_map) = - self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); - let skol_obligation_trait_ref = skol_obligation.trait_ref; - - let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); - - let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); - - let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = - project::normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &impl_trait_ref, - ); - - debug!( - "match_impl(impl_def_id={:?}, obligation={:?}, \ - impl_trait_ref={:?}, skol_obligation_trait_ref={:?})", - impl_def_id, obligation, impl_trait_ref, skol_obligation_trait_ref - ); - - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(skol_obligation_trait_ref, impl_trait_ref) - .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?; - nested_obligations.extend(obligations); - - if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) { - debug!("match_impl: failed leak check due to `{}`", e); - return Err(()); - } - - if !self.intercrate - && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation - { - debug!("match_impl: reservation impls only apply in intercrate mode"); - return Err(()); - } - - debug!("match_impl: success impl_substs={:?}", impl_substs); - Ok(Normalized { value: impl_substs, obligations: nested_obligations }) - } - - fn fast_reject_trait_refs( - &mut self, - obligation: &TraitObligation<'_>, - impl_trait_ref: &ty::TraitRef<'_>, - ) -> bool { - // We can avoid creating type variables and doing the full - // substitution if we find that any of the input types, when - // simplified, do not match. - - obligation.predicate.skip_binder().input_types().zip(impl_trait_ref.input_types()).any( - |(obligation_ty, impl_ty)| { - let simplified_obligation_ty = - fast_reject::simplify_type(self.tcx(), obligation_ty, true); - let simplified_impl_ty = fast_reject::simplify_type(self.tcx(), impl_ty, false); - - simplified_obligation_ty.is_some() - && simplified_impl_ty.is_some() - && simplified_obligation_ty != simplified_impl_ty - }, - ) - } - - /// Normalize `where_clause_trait_ref` and try to match it against - /// `obligation`. If successful, return any predicates that - /// result from the normalization. Normalization is necessary - /// because where-clauses are stored in the parameter environment - /// unnormalized. - fn match_where_clause_trait_ref( - &mut self, - obligation: &TraitObligation<'tcx>, - where_clause_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result>, ()> { - self.match_poly_trait_ref(obligation, where_clause_trait_ref) - } - - /// Returns `Ok` if `poly_trait_ref` being true implies that the - /// obligation is satisfied. - fn match_poly_trait_ref( - &mut self, - obligation: &TraitObligation<'tcx>, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result>, ()> { - debug!( - "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}", - obligation, poly_trait_ref - ); + // FIXME: when an `EvaluatedToRecur` goes past its parent root, we + // ought to convert it to an `EvaluatedToErr`, because we know + // there definitely isn't a proof tree for that obligation. Not + // doing so is still sound -- there isn't any proof tree, so the + // branch still can't be a part of a minimal one -- but does not re-enable caching. + EvaluatedToRecur, + /// Evaluation failed. + EvaluatedToErr, +} - self.infcx - .at(&obligation.cause, obligation.param_env) - .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) - .map(|InferOk { obligations, .. }| obligations) - .map_err(|_| ()) +impl EvaluationResult { + /// Returns `true` if this evaluation result is known to apply, even + /// considering outlives constraints. + pub fn must_apply_considering_regions(self) -> bool { + self == EvaluatedToOk } - /////////////////////////////////////////////////////////////////////////// - // Miscellany - - fn match_fresh_trait_refs( - &self, - previous: &ty::PolyTraitRef<'tcx>, - current: &ty::PolyTraitRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> bool { - let mut matcher = ty::_match::Match::new(self.tcx(), param_env); - matcher.relate(previous, current).is_ok() + /// Returns `true` if this evaluation result is known to apply, ignoring + /// outlives constraints. + pub fn must_apply_modulo_regions(self) -> bool { + self <= EvaluatedToOkModuloRegions } - fn push_stack<'o>( - &mut self, - previous_stack: TraitObligationStackList<'o, 'tcx>, - obligation: &'o TraitObligation<'tcx>, - ) -> TraitObligationStack<'o, 'tcx> { - let fresh_trait_ref = - obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener); + pub fn may_apply(self) -> bool { + match self { + EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => { + true + } - let dfn = previous_stack.cache.next_dfn(); - let depth = previous_stack.depth() + 1; - TraitObligationStack { - obligation, - fresh_trait_ref, - reached_depth: Cell::new(depth), - previous: previous_stack, - dfn, - depth, + EvaluatedToErr | EvaluatedToRecur => false, } } - fn closure_trait_ref_unnormalized( - &mut self, - obligation: &TraitObligation<'tcx>, - closure_def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> ty::PolyTraitRef<'tcx> { - debug!( - "closure_trait_ref_unnormalized(obligation={:?}, closure_def_id={:?}, substs={:?})", - obligation, closure_def_id, substs, - ); - let closure_type = self.infcx.closure_sig(closure_def_id, substs); - - debug!("closure_trait_ref_unnormalized: closure_type = {:?}", closure_type); - - // (1) Feels icky to skip the binder here, but OTOH we know - // that the self-type is an unboxed closure type and hence is - // in fact unparameterized (or at least does not reference any - // regions bound in the obligation). Still probably some - // refactoring could make this nicer. - closure_trait_ref_and_return_type( - self.tcx(), - obligation.predicate.def_id(), - obligation.predicate.skip_binder().self_ty(), // (1) - closure_type, - util::TupleArgumentsFlag::No, - ) - .map_bound(|(trait_ref, _)| trait_ref) - } - - fn generator_trait_ref_unnormalized( - &mut self, - obligation: &TraitObligation<'tcx>, - closure_def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> ty::PolyTraitRef<'tcx> { - let gen_sig = substs.as_generator().poly_sig(closure_def_id, self.tcx()); - - // (1) Feels icky to skip the binder here, but OTOH we know - // that the self-type is an generator type and hence is - // in fact unparameterized (or at least does not reference any - // regions bound in the obligation). Still probably some - // refactoring could make this nicer. - - super::util::generator_trait_ref_and_outputs( - self.tcx(), - obligation.predicate.def_id(), - obligation.predicate.skip_binder().self_ty(), // (1) - gen_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref) - } - - /// Returns the obligations that are implied by instantiating an - /// impl or trait. The obligations are substituted and fully - /// normalized. This is used when confirming an impl or default - /// impl. - fn impl_or_trait_obligations( - &mut self, - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - def_id: DefId, // of impl or trait - substs: SubstsRef<'tcx>, // for impl or trait - ) -> Vec> { - debug!("impl_or_trait_obligations(def_id={:?})", def_id); - let tcx = self.tcx(); - - // To allow for one-pass evaluation of the nested obligation, - // each predicate must be preceded by the obligations required - // to normalize it. - // for example, if we have: - // impl, V: Iterator> Foo for V - // the impl will have the following predicates: - // ::Item = U, - // U: Iterator, U: Sized, - // V: Iterator, V: Sized, - // ::Item: Copy - // When we substitute, say, `V => IntoIter, U => $0`, the last - // obligation will normalize to `<$0 as Iterator>::Item = $1` and - // `$1: Copy`, so we must ensure the obligations are emitted in - // that order. - let predicates = tcx.predicates_of(def_id); - assert_eq!(predicates.parent, None); - let mut obligations = Vec::with_capacity(predicates.predicates.len()); - for (predicate, _) in predicates.predicates { - let predicate = normalize_with_depth_to( - self, - param_env, - cause.clone(), - recursion_depth, - &predicate.subst(tcx, substs), - &mut obligations, - ); - obligations.push(Obligation { - cause: cause.clone(), - recursion_depth, - param_env, - predicate, - }); - } + pub fn is_stack_dependent(self) -> bool { + match self { + EvaluatedToUnknown | EvaluatedToRecur => true, - // We are performing deduplication here to avoid exponential blowups - // (#38528) from happening, but the real cause of the duplication is - // unknown. What we know is that the deduplication avoids exponential - // amount of predicates being propagated when processing deeply nested - // types. - // - // This code is hot enough that it's worth avoiding the allocation - // required for the FxHashSet when possible. Special-casing lengths 0, - // 1 and 2 covers roughly 75-80% of the cases. - if obligations.len() <= 1 { - // No possibility of duplicates. - } else if obligations.len() == 2 { - // Only two elements. Drop the second if they are equal. - if obligations[0] == obligations[1] { - obligations.truncate(1); - } - } else { - // Three or more elements. Use a general deduplication process. - let mut seen = FxHashSet::default(); - obligations.retain(|i| seen.insert(i.clone())); + EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false, } - - obligations - } -} - -impl<'tcx> TraitObligation<'tcx> { - #[allow(unused_comparisons)] - pub fn derived_cause( - &self, - variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, - ) -> ObligationCause<'tcx> { - /*! - * Creates a cause for obligations that are derived from - * `obligation` by a recursive search (e.g., for a builtin - * bound, or eventually a `auto trait Foo`). If `obligation` - * is itself a derived obligation, this is just a clone, but - * otherwise we create a "derived obligation" cause so as to - * keep track of the original root obligation for error - * reporting. - */ - - let obligation = self; - - // NOTE(flaper87): As of now, it keeps track of the whole error - // chain. Ideally, we should have a way to configure this either - // by using -Z verbose or just a CLI argument. - let derived_cause = DerivedObligationCause { - parent_trait_ref: obligation.predicate.to_poly_trait_ref(), - parent_code: Rc::new(obligation.cause.code.clone()), - }; - let derived_code = variant(derived_cause); - ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) } } -impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { - fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> { - TraitObligationStackList::with(self) - } - - fn cache(&self) -> &'o ProvisionalEvaluationCache<'tcx> { - self.previous.cache - } - - fn iter(&'o self) -> TraitObligationStackList<'o, 'tcx> { - self.list() - } +/// Indicates that trait evaluation caused overflow. +#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)] +pub struct OverflowError; - /// Indicates that attempting to evaluate this stack entry - /// required accessing something from the stack at depth `reached_depth`. - fn update_reached_depth(&self, reached_depth: usize) { - assert!( - self.depth > reached_depth, - "invoked `update_reached_depth` with something under this stack: \ - self.depth={} reached_depth={}", - self.depth, - reached_depth, - ); - debug!("update_reached_depth(reached_depth={})", reached_depth); - let mut p = self; - while reached_depth < p.depth { - debug!("update_reached_depth: marking {:?} as cycle participant", p.fresh_trait_ref); - p.reached_depth.set(p.reached_depth.get().min(reached_depth)); - p = p.previous.head.unwrap(); - } +impl<'tcx> From for SelectionError<'tcx> { + fn from(OverflowError: OverflowError) -> SelectionError<'tcx> { + SelectionError::Overflow } } -/// The "provisional evaluation cache" is used to store intermediate cache results -/// when solving auto traits. Auto traits are unusual in that they can support -/// cycles. So, for example, a "proof tree" like this would be ok: -/// -/// - `Foo: Send` :- -/// - `Bar: Send` :- -/// - `Foo: Send` -- cycle, but ok -/// - `Baz: Send` -/// -/// Here, to prove `Foo: Send`, we have to prove `Bar: Send` and -/// `Baz: Send`. Proving `Bar: Send` in turn required `Foo: Send`. -/// For non-auto traits, this cycle would be an error, but for auto traits (because -/// they are coinductive) it is considered ok. -/// -/// However, there is a complication: at the point where we have -/// "proven" `Bar: Send`, we have in fact only proven it -/// *provisionally*. In particular, we proved that `Bar: Send` -/// *under the assumption* that `Foo: Send`. But what if we later -/// find out this assumption is wrong? Specifically, we could -/// encounter some kind of error proving `Baz: Send`. In that case, -/// `Bar: Send` didn't turn out to be true. -/// -/// In Issue #60010, we found a bug in rustc where it would cache -/// these intermediate results. This was fixed in #60444 by disabling -/// *all* caching for things involved in a cycle -- in our example, -/// that would mean we don't cache that `Bar: Send`. But this led -/// to large slowdowns. -/// -/// Specifically, imagine this scenario, where proving `Baz: Send` -/// first requires proving `Bar: Send` (which is true: -/// -/// - `Foo: Send` :- -/// - `Bar: Send` :- -/// - `Foo: Send` -- cycle, but ok -/// - `Baz: Send` -/// - `Bar: Send` -- would be nice for this to be a cache hit! -/// - `*const T: Send` -- but what if we later encounter an error? -/// -/// The *provisional evaluation cache* resolves this issue. It stores -/// cache results that we've proven but which were involved in a cycle -/// in some way. We track the minimal stack depth (i.e., the -/// farthest from the top of the stack) that we are dependent on. -/// The idea is that the cache results within are all valid -- so long as -/// none of the nodes in between the current node and the node at that minimum -/// depth result in an error (in which case the cached results are just thrown away). -/// -/// During evaluation, we consult this provisional cache and rely on -/// it. Accessing a cached value is considered equivalent to accessing -/// a result at `reached_depth`, so it marks the *current* solution as -/// provisional as well. If an error is encountered, we toss out any -/// provisional results added from the subtree that encountered the -/// error. When we pop the node at `reached_depth` from the stack, we -/// can commit all the things that remain in the provisional cache. -struct ProvisionalEvaluationCache<'tcx> { - /// next "depth first number" to issue -- just a counter - dfn: Cell, - - /// Stores the "coldest" depth (bottom of stack) reached by any of - /// the evaluation entries. The idea here is that all things in the provisional - /// cache are always dependent on *something* that is colder in the stack: - /// therefore, if we add a new entry that is dependent on something *colder still*, - /// we have to modify the depth for all entries at once. - /// - /// Example: - /// - /// Imagine we have a stack `A B C D E` (with `E` being the top of - /// the stack). We cache something with depth 2, which means that - /// it was dependent on C. Then we pop E but go on and process a - /// new node F: A B C D F. Now F adds something to the cache with - /// depth 1, meaning it is dependent on B. Our original cache - /// entry is also dependent on B, because there is a path from E - /// to C and then from C to F and from F to B. - reached_depth: Cell, - - /// Map from cache key to the provisionally evaluated thing. - /// The cache entries contain the result but also the DFN in which they - /// were added. The DFN is used to clear out values on failure. - /// - /// Imagine we have a stack like: - /// - /// - `A B C` and we add a cache for the result of C (DFN 2) - /// - Then we have a stack `A B D` where `D` has DFN 3 - /// - We try to solve D by evaluating E: `A B D E` (DFN 4) - /// - `E` generates various cache entries which have cyclic dependices on `B` - /// - `A B D E F` and so forth - /// - the DFN of `F` for example would be 5 - /// - then we determine that `E` is in error -- we will then clear - /// all cache values whose DFN is >= 4 -- in this case, that - /// means the cached value for `F`. - map: RefCell, ProvisionalEvaluation>>, -} - -/// A cache value for the provisional cache: contains the depth-first -/// number (DFN) and result. -#[derive(Copy, Clone, Debug)] -struct ProvisionalEvaluation { - from_dfn: usize, - result: EvaluationResult, +#[derive(Clone, Default)] +pub struct EvaluationCache<'tcx> { + pub hashmap: Lock< + FxHashMap>, WithDepNode>, + >, } -impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> { - fn default() -> Self { - Self { - dfn: Cell::new(0), - reached_depth: Cell::new(std::usize::MAX), - map: Default::default(), - } +impl<'tcx> EvaluationCache<'tcx> { + /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear` + pub fn clear(&self) { + *self.hashmap.borrow_mut() = Default::default(); } } -impl<'tcx> ProvisionalEvaluationCache<'tcx> { - /// Get the next DFN in sequence (basically a counter). - fn next_dfn(&self) -> usize { - let result = self.dfn.get(); - self.dfn.set(result + 1); - result - } - - /// Check the provisional cache for any result for - /// `fresh_trait_ref`. If there is a hit, then you must consider - /// it an access to the stack slots at depth - /// `self.current_reached_depth()` and above. - fn get_provisional(&self, fresh_trait_ref: ty::PolyTraitRef<'tcx>) -> Option { - debug!( - "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}", - fresh_trait_ref, - self.map.borrow().get(&fresh_trait_ref), - self.reached_depth.get(), - ); - Some(self.map.borrow().get(&fresh_trait_ref)?.result) - } - - /// Current value of the `reached_depth` counter -- all the - /// provisional cache entries are dependent on the item at this - /// depth. - fn current_reached_depth(&self) -> usize { - self.reached_depth.get() - } - - /// Insert a provisional result into the cache. The result came - /// from the node with the given DFN. It accessed a minimum depth - /// of `reached_depth` to compute. It evaluated `fresh_trait_ref` - /// and resulted in `result`. - fn insert_provisional( - &self, - from_dfn: usize, - reached_depth: usize, - fresh_trait_ref: ty::PolyTraitRef<'tcx>, - result: EvaluationResult, - ) { - debug!( - "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})", - from_dfn, reached_depth, fresh_trait_ref, result, - ); - let r_d = self.reached_depth.get(); - self.reached_depth.set(r_d.min(reached_depth)); - - debug!("insert_provisional: reached_depth={:?}", self.reached_depth.get()); - - self.map.borrow_mut().insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, result }); - } +#[derive(Clone, Eq, PartialEq)] +pub struct WithDepNode { + dep_node: DepNodeIndex, + cached_value: T, +} - /// Invoked when the node with dfn `dfn` does not get a successful - /// result. This will clear out any provisional cache entries - /// that were added since `dfn` was created. This is because the - /// provisional entries are things which must assume that the - /// things on the stack at the time of their creation succeeded -- - /// since the failing node is presently at the top of the stack, - /// these provisional entries must either depend on it or some - /// ancestor of it. - fn on_failure(&self, dfn: usize) { - debug!("on_failure(dfn={:?})", dfn,); - self.map.borrow_mut().retain(|key, eval| { - if !eval.from_dfn >= dfn { - debug!("on_failure: removing {:?}", key); - false - } else { - true - } - }); +impl WithDepNode { + pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self { + WithDepNode { dep_node, cached_value } } - /// Invoked when the node at depth `depth` completed without - /// depending on anything higher in the stack (if that completion - /// was a failure, then `on_failure` should have been invoked - /// already). The callback `op` will be invoked for each - /// provisional entry that we can now confirm. - fn on_completion( - &self, - depth: usize, - mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult), - ) { - debug!("on_completion(depth={}, reached_depth={})", depth, self.reached_depth.get(),); - - if self.reached_depth.get() < depth { - debug!("on_completion: did not yet reach depth to complete"); - return; - } - - for (fresh_trait_ref, eval) in self.map.borrow_mut().drain() { - debug!("on_completion: fresh_trait_ref={:?} eval={:?}", fresh_trait_ref, eval,); - - op(fresh_trait_ref, eval.result); - } - - self.reached_depth.set(std::usize::MAX); + pub fn get(&self, tcx: TyCtxt<'_>) -> T { + tcx.dep_graph.read_index(self.dep_node); + self.cached_value.clone() } } -#[derive(Copy, Clone)] -struct TraitObligationStackList<'o, 'tcx> { - cache: &'o ProvisionalEvaluationCache<'tcx>, - head: Option<&'o TraitObligationStack<'o, 'tcx>>, +#[derive(Clone, Debug)] +pub enum IntercrateAmbiguityCause { + DownstreamCrate { trait_desc: String, self_desc: Option }, + UpstreamCrateUpdate { trait_desc: String, self_desc: Option }, + ReservationImpl { message: String }, } -impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> { - fn empty(cache: &'o ProvisionalEvaluationCache<'tcx>) -> TraitObligationStackList<'o, 'tcx> { - TraitObligationStackList { cache, head: None } - } - - fn with(r: &'o TraitObligationStack<'o, 'tcx>) -> TraitObligationStackList<'o, 'tcx> { - TraitObligationStackList { cache: r.cache(), head: Some(r) } - } - - fn head(&self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { - self.head - } - - fn depth(&self) -> usize { - if let Some(head) = self.head { head.depth } else { 0 } +impl IntercrateAmbiguityCause { + /// Emits notes when the overlap is caused by complex intercrate ambiguities. + /// See #23980 for details. + pub fn add_intercrate_ambiguity_hint(&self, err: &mut rustc_errors::DiagnosticBuilder<'_>) { + err.note(&self.intercrate_ambiguity_hint()); } -} -impl<'o, 'tcx> Iterator for TraitObligationStackList<'o, 'tcx> { - type Item = &'o TraitObligationStack<'o, 'tcx>; - - fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { - match self.head { - Some(o) => { - *self = o.previous; - Some(o) + pub fn intercrate_ambiguity_hint(&self) -> String { + match self { + &IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => { + let self_desc = if let &Some(ref ty) = self_desc { + format!(" for type `{}`", ty) + } else { + String::new() + }; + format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc) } - None => None, + &IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => { + let self_desc = if let &Some(ref ty) = self_desc { + format!(" for type `{}`", ty) + } else { + String::new() + }; + format!( + "upstream crates may add a new impl of trait `{}`{} \ + in future versions", + trait_desc, self_desc + ) + } + &IntercrateAmbiguityCause::ReservationImpl { ref message } => message.clone(), } } } - -impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "TraitObligationStack({:?})", self.obligation) - } -} diff --git a/src/librustc/traits/types/specialization_graph.rs b/src/librustc/traits/specialization_graph.rs similarity index 86% rename from src/librustc/traits/types/specialization_graph.rs rename to src/librustc/traits/specialization_graph.rs index 36a84369d4a..1847326a742 100644 --- a/src/librustc/traits/types/specialization_graph.rs +++ b/src/librustc/traits/specialization_graph.rs @@ -1,10 +1,11 @@ use crate::ich::{self, StableHashingContext}; use crate::ty::fast_reject::SimplifiedType; use crate::ty::{self, TyCtxt}; +use rustc_ast::ast::Ident; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_errors::ErrorReported; use rustc_hir::def_id::{DefId, DefIdMap}; -use syntax::ast::Ident; /// A per-trait graph of impls in specialization order. At the moment, this /// graph forms a tree rooted with the trait itself, with all other nodes @@ -23,17 +24,20 @@ use syntax::ast::Ident; /// has at most one parent. #[derive(RustcEncodable, RustcDecodable, HashStable)] pub struct Graph { - // All impls have a parent; the "root" impls have as their parent the `def_id` - // of the trait. + /// All impls have a parent; the "root" impls have as their parent the `def_id` + /// of the trait. pub parent: DefIdMap, - // The "root" impls are found by looking up the trait's def_id. + /// The "root" impls are found by looking up the trait's def_id. pub children: DefIdMap, + + /// Whether an error was emitted while constructing the graph. + pub has_errored: bool, } impl Graph { pub fn new() -> Graph { - Graph { parent: Default::default(), children: Default::default() } + Graph { parent: Default::default(), children: Default::default(), has_errored: false } } /// The parent of a given impl, which is the `DefId` of the trait when the @@ -81,8 +85,8 @@ impl<'tcx> Node { } /// Iterate over the items defined directly by the given (impl or trait) node. - pub fn items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [ty::AssocItem] { - tcx.associated_items(self.def_id()) + pub fn items(&self, tcx: TyCtxt<'tcx>) -> impl 'tcx + Iterator { + tcx.associated_items(self.def_id()).in_definition_order() } /// Finds an associated item defined in this node. @@ -99,7 +103,7 @@ impl<'tcx> Node { use crate::ty::AssocKind::*; tcx.associated_items(self.def_id()) - .iter() + .filter_by_name_unhygienic(trait_item_name.name) .find(move |impl_item| { match (trait_item_kind, impl_item.kind) { | (Const, Const) @@ -179,17 +183,22 @@ impl<'tcx> Ancestors<'tcx> { } /// Walk up the specialization ancestors of a given impl, starting with that -/// impl itself. +/// impl itself. Returns `None` if an error was reported while building the +/// specialization graph. pub fn ancestors( tcx: TyCtxt<'tcx>, trait_def_id: DefId, start_from_impl: DefId, -) -> Ancestors<'tcx> { +) -> Result, ErrorReported> { let specialization_graph = tcx.specialization_graph_of(trait_def_id); - Ancestors { - trait_def_id, - specialization_graph, - current_source: Some(Node::Impl(start_from_impl)), + if specialization_graph.has_errored { + Err(ErrorReported) + } else { + Ok(Ancestors { + trait_def_id, + specialization_graph, + current_source: Some(Node::Impl(start_from_impl)), + }) } } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 80731c7b189..a5efea9e5fa 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -1,71 +1,640 @@ use crate::traits; -use crate::traits::project::Normalized; -use crate::ty; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use crate::ty::{self, Lift, Ty, TyCtxt}; +use rustc_span::symbol::Symbol; +use smallvec::SmallVec; +use std::collections::{BTreeMap, BTreeSet}; use std::fmt; +use std::rc::Rc; // Structural impls for the structs in `traits`. -impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Normalized({:?}, {:?})", self.value, self.obligations) + match *self { + super::VtableImpl(ref v) => write!(f, "{:?}", v), + + super::VtableAutoImpl(ref t) => write!(f, "{:?}", t), + + super::VtableClosure(ref d) => write!(f, "{:?}", d), + + super::VtableGenerator(ref d) => write!(f, "{:?}", d), + + super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d), + + super::VtableObject(ref d) => write!(f, "{:?}", d), + + super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n), + + super::VtableBuiltin(ref d) => write!(f, "{:?}", d), + + super::VtableTraitAlias(ref d) => write!(f, "{:?}", d), + } } } -impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if ty::tls::with(|tcx| tcx.sess.verbose()) { - write!( - f, - "Obligation(predicate={:?}, cause={:?}, param_env={:?}, depth={})", - self.predicate, self.cause, self.param_env, self.recursion_depth - ) - } else { - write!(f, "Obligation(predicate={:?}, depth={})", self.predicate, self.recursion_depth) - } + write!( + f, + "VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})", + self.impl_def_id, self.substs, self.nested + ) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})", + self.generator_def_id, self.substs, self.nested + ) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})", + self.closure_def_id, self.substs, self.nested + ) + } +} + +impl fmt::Debug for traits::VtableBuiltinData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "VtableBuiltinData(nested={:?})", self.nested) + } +} + +impl fmt::Debug for traits::VtableAutoImplData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VtableAutoImplData(trait_def_id={:?}, nested={:?})", + self.trait_def_id, self.nested + ) } } -impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code) + write!( + f, + "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})", + self.upcast_trait_ref, self.vtable_base, self.nested + ) } } -impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "VtableFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})", + self.alias_def_id, self.substs, self.nested + ) + } +} + +impl<'tcx> fmt::Display for traits::WhereClause<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::WhereClause::*; + + // Bypass `ty::print` because it does not print out anonymous regions. + // FIXME(eddyb) implement a custom `PrettyPrinter`, or move this to `ty::print`. + fn write_region_name<'tcx>( + r: ty::Region<'tcx>, + fmt: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + match r { + ty::ReLateBound(index, br) => match br { + ty::BoundRegion::BrNamed(_, name) => write!(fmt, "{}", name), + ty::BoundRegion::BrAnon(var) => { + if *index == ty::INNERMOST { + write!(fmt, "'^{}", var) + } else { + write!(fmt, "'^{}_{}", index.index(), var) + } + } + _ => write!(fmt, "'_"), + }, + + _ => write!(fmt, "{}", r), + } + } + + match self { + Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref), + ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection), + RegionOutlives(predicate) => { + write!(fmt, "RegionOutlives({}: ", predicate.0)?; + write_region_name(predicate.1, fmt)?; + write!(fmt, ")") + } + TypeOutlives(predicate) => { + write!(fmt, "TypeOutlives({}: ", predicate.0)?; + write_region_name(predicate.1, fmt)?; + write!(fmt, ")") + } + } + } +} + +impl<'tcx> fmt::Display for traits::WellFormed<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::WellFormed::*; + + match self { + Trait(trait_ref) => write!(fmt, "WellFormed({})", trait_ref), + Ty(ty) => write!(fmt, "WellFormed({})", ty), + } + } +} + +impl<'tcx> fmt::Display for traits::FromEnv<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::FromEnv::*; + + match self { + Trait(trait_ref) => write!(fmt, "FromEnv({})", trait_ref), + Ty(ty) => write!(fmt, "FromEnv({})", ty), + } + } +} + +impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::DomainGoal::*; + + match self { + Holds(wc) => write!(fmt, "{}", wc), + WellFormed(wf) => write!(fmt, "{}", wf), + FromEnv(from_env) => write!(fmt, "{}", from_env), + Normalize(projection) => { + write!(fmt, "Normalize({} -> {})", projection.projection_ty, projection.ty) + } + } + } +} + +impl fmt::Display for traits::QuantifierKind { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::QuantifierKind::*; + + match self { + Universal => write!(fmt, "forall"), + Existential => write!(fmt, "exists"), + } + } +} + +/// Collect names for regions / types bound by a quantified goal / clause. +/// This collector does not try to do anything clever like in `ty::print`, it's just used +/// for debug output in tests anyway. +struct BoundNamesCollector { + // Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway. + regions: BTreeSet, + + // Sort by `BoundVar` index, so usually this should be equivalent to the order given + // by the list of type parameters. + types: BTreeMap, + + binder_index: ty::DebruijnIndex, +} + +impl BoundNamesCollector { + fn new() -> Self { + BoundNamesCollector { + regions: BTreeSet::new(), + types: BTreeMap::new(), + binder_index: ty::INNERMOST, + } + } + + fn is_empty(&self) -> bool { + self.regions.is_empty() && self.types.is_empty() + } + + fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut start = true; + for r in &self.regions { + if !start { + write!(fmt, ", ")?; + } + start = false; + write!(fmt, "{}", r)?; + } + for t in self.types.values() { + if !start { + write!(fmt, ", ")?; + } + start = false; + write!(fmt, "{}", t)?; + } + Ok(()) + } +} + +impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector { + fn visit_binder>(&mut self, t: &ty::Binder) -> bool { + self.binder_index.shift_in(1); + let result = t.super_visit_with(self); + self.binder_index.shift_out(1); + result + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.kind { + ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { + self.types.insert( + bound_ty.var.as_u32(), + match bound_ty.kind { + ty::BoundTyKind::Param(name) => name, + ty::BoundTyKind::Anon => { + Symbol::intern(&format!("^{}", bound_ty.var.as_u32())) + } + }, + ); + } + + _ => (), + }; + + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + match r { + ty::ReLateBound(index, br) if *index == self.binder_index => match br { + ty::BoundRegion::BrNamed(_, name) => { + self.regions.insert(*name); + } + + ty::BoundRegion::BrAnon(var) => { + self.regions.insert(Symbol::intern(&format!("'^{}", var))); + } + + _ => (), + }, + + _ => (), + }; + + r.super_visit_with(self) + } +} + +impl<'tcx> fmt::Display for traits::Goal<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::GoalKind::*; + + match self { + Implies(hypotheses, goal) => { + write!(fmt, "if (")?; + for (index, hyp) in hypotheses.iter().enumerate() { + if index > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{}", hyp)?; + } + write!(fmt, ") {{ {} }}", goal) + } + And(goal1, goal2) => write!(fmt, "({} && {})", goal1, goal2), + Not(goal) => write!(fmt, "not {{ {} }}", goal), + DomainGoal(goal) => write!(fmt, "{}", goal), + Quantified(qkind, goal) => { + let mut collector = BoundNamesCollector::new(); + goal.skip_binder().visit_with(&mut collector); + + if !collector.is_empty() { + write!(fmt, "{}<", qkind)?; + collector.write_names(fmt)?; + write!(fmt, "> {{ ")?; + } + + write!(fmt, "{}", goal.skip_binder())?; + + if !collector.is_empty() { + write!(fmt, " }}")?; + } + + Ok(()) + } + Subtype(a, b) => write!(fmt, "{} <: {}", a, b), + CannotProve => write!(fmt, "CannotProve"), + } + } +} + +impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let traits::ProgramClause { goal, hypotheses, .. } = self; + write!(fmt, "{}", goal)?; + if !hypotheses.is_empty() { + write!(fmt, " :- ")?; + for (index, condition) in hypotheses.iter().enumerate() { + if index > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{}", condition)?; + } + } + write!(fmt, ".") + } +} + +impl<'tcx> fmt::Display for traits::Clause<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + use crate::traits::Clause::*; + + match self { + Implies(clause) => write!(fmt, "{}", clause), + ForAll(clause) => { + let mut collector = BoundNamesCollector::new(); + clause.skip_binder().visit_with(&mut collector); + + if !collector.is_empty() { + write!(fmt, "forall<")?; + collector.write_names(fmt)?; + write!(fmt, "> {{ ")?; + } + + write!(fmt, "{}", clause.skip_binder())?; + + if !collector.is_empty() { + write!(fmt, " }}")?; + } + + Ok(()) + } + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Lift implementations + +impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> { + type Lifted = traits::SelectionError<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { match *self { - super::CodeSelectionError(ref e) => write!(f, "{:?}", e), - super::CodeProjectionError(ref e) => write!(f, "{:?}", e), - super::CodeSubtypeError(ref a, ref b) => { - write!(f, "CodeSubtypeError({:?}, {:?})", a, b) + super::Unimplemented => Some(super::Unimplemented), + super::OutputTypeParameterMismatch(a, b, ref err) => { + tcx.lift(&(a, b)).and_then(|(a, b)| { + tcx.lift(err).map(|err| super::OutputTypeParameterMismatch(a, b, err)) + }) } - super::CodeAmbiguity => write!(f, "Ambiguity"), + super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)), + super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)), + super::Overflow => Some(super::Overflow), } } } -impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "MismatchedProjectionTypes({:?})", self.err) +impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { + type Lifted = traits::ObligationCauseCode<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { + match *self { + super::ReturnNoExpression => Some(super::ReturnNoExpression), + super::MiscObligation => Some(super::MiscObligation), + super::SliceOrArrayElem => Some(super::SliceOrArrayElem), + super::TupleElem => Some(super::TupleElem), + super::ProjectionWf(proj) => tcx.lift(&proj).map(super::ProjectionWf), + super::ItemObligation(def_id) => Some(super::ItemObligation(def_id)), + super::BindingObligation(def_id, span) => Some(super::BindingObligation(def_id, span)), + super::ReferenceOutlivesReferent(ty) => { + tcx.lift(&ty).map(super::ReferenceOutlivesReferent) + } + super::ObjectTypeBound(ty, r) => { + tcx.lift(&ty).and_then(|ty| tcx.lift(&r).map(|r| super::ObjectTypeBound(ty, r))) + } + super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation), + super::Coercion { source, target } => { + Some(super::Coercion { source: tcx.lift(&source)?, target: tcx.lift(&target)? }) + } + super::AssignmentLhsSized => Some(super::AssignmentLhsSized), + super::TupleInitializerSized => Some(super::TupleInitializerSized), + super::StructInitializerSized => Some(super::StructInitializerSized), + super::VariableType(id) => Some(super::VariableType(id)), + super::ReturnValue(id) => Some(super::ReturnValue(id)), + super::ReturnType => Some(super::ReturnType), + super::SizedArgumentType => Some(super::SizedArgumentType), + super::SizedReturnType => Some(super::SizedReturnType), + super::SizedYieldType => Some(super::SizedYieldType), + super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)), + super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }), + super::ConstSized => Some(super::ConstSized), + super::ConstPatternStructural => Some(super::ConstPatternStructural), + super::SharedStatic => Some(super::SharedStatic), + super::BuiltinDerivedObligation(ref cause) => { + tcx.lift(cause).map(super::BuiltinDerivedObligation) + } + super::ImplDerivedObligation(ref cause) => { + tcx.lift(cause).map(super::ImplDerivedObligation) + } + super::CompareImplMethodObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + } => Some(super::CompareImplMethodObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + }), + super::CompareImplTypeObligation { item_name, impl_item_def_id, trait_item_def_id } => { + Some(super::CompareImplTypeObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + }) + } + super::ExprAssignable => Some(super::ExprAssignable), + super::MatchExpressionArm(box super::MatchExpressionArmCause { + arm_span, + source, + ref prior_arms, + last_ty, + scrut_hir_id, + }) => tcx.lift(&last_ty).map(|last_ty| { + super::MatchExpressionArm(box super::MatchExpressionArmCause { + arm_span, + source, + prior_arms: prior_arms.clone(), + last_ty, + scrut_hir_id, + }) + }), + super::Pattern { span, root_ty, origin_expr } => { + tcx.lift(&root_ty).map(|root_ty| super::Pattern { span, root_ty, origin_expr }) + } + super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => { + Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon })) + } + super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse), + super::MainFunctionType => Some(super::MainFunctionType), + super::StartFunctionType => Some(super::StartFunctionType), + super::IntrinsicType => Some(super::IntrinsicType), + super::MethodReceiver => Some(super::MethodReceiver), + super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)), + super::TrivialBound => Some(super::TrivialBound), + super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())), + } + } +} + +impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> { + type Lifted = traits::DerivedObligationCause<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { + tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| { + tcx.lift(&*self.parent_code).map(|code| traits::DerivedObligationCause { + parent_trait_ref: trait_ref, + parent_code: Rc::new(code), + }) + }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> { + type Lifted = traits::ObligationCause<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { + tcx.lift(&self.code).map(|code| traits::ObligationCause { + span: self.span, + body_id: self.body_id, + code, + }) + } +} + +// For codegen only. +impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { + type Lifted = traits::Vtable<'tcx, ()>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { + match self.clone() { + traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) => { + tcx.lift(&substs).map(|substs| { + traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) + }) + } + traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)), + traits::VtableGenerator(traits::VtableGeneratorData { + generator_def_id, + substs, + nested, + }) => tcx.lift(&substs).map(|substs| { + traits::VtableGenerator(traits::VtableGeneratorData { + generator_def_id, + substs, + nested, + }) + }), + traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested }) => { + tcx.lift(&substs).map(|substs| { + traits::VtableClosure(traits::VtableClosureData { + closure_def_id, + substs, + nested, + }) + }) + } + traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => { + tcx.lift(&fn_ty).map(|fn_ty| { + traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) + }) + } + traits::VtableParam(n) => Some(traits::VtableParam(n)), + traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)), + traits::VtableObject(traits::VtableObjectData { + upcast_trait_ref, + vtable_base, + nested, + }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| { + traits::VtableObject(traits::VtableObjectData { + upcast_trait_ref: trait_ref, + vtable_base, + nested, + }) + }), + traits::VtableTraitAlias(traits::VtableTraitAliasData { + alias_def_id, + substs, + nested, + }) => tcx.lift(&substs).map(|substs| { + traits::VtableTraitAlias(traits::VtableTraitAliasData { + alias_def_id, + substs, + nested, + }) + }), + } + } +} + +impl<'a, 'tcx> Lift<'tcx> for traits::Environment<'a> { + type Lifted = traits::Environment<'tcx>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { + tcx.lift(&self.clauses).map(|clauses| traits::Environment { clauses }) + } +} + +impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> { + type Lifted = traits::InEnvironment<'tcx, G::Lifted>; + fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { + tcx.lift(&self.environment).and_then(|environment| { + tcx.lift(&self.goal).map(|goal| traits::InEnvironment { environment, goal }) + }) } } /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. -impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> { +CloneTypeFoldableAndLiftImpls! { + traits::QuantifierKind, +} + +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { fn super_fold_with>(&self, folder: &mut F) -> Self { - traits::Obligation { - cause: self.cause.clone(), - recursion_depth: self.recursion_depth, - predicate: self.predicate.fold_with(folder), - param_env: self.param_env.fold_with(folder), - } + let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); + folder.tcx().intern_goals(&v) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} + +impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + let v = (**self).fold_with(folder); + folder.tcx().mk_goal(v) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + (**self).visit_with(visitor) + } +} + +CloneTypeFoldableAndLiftImpls! { + traits::ProgramClauseCategory, +} + +impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); + folder.tcx().intern_clauses(&v) } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.predicate.visit_with(visitor) + self.iter().any(|t| t.visit_with(visitor)) } } diff --git a/src/librustc/traits/types/mod.rs b/src/librustc/traits/types/mod.rs deleted file mode 100644 index 571fb505779..00000000000 --- a/src/librustc/traits/types/mod.rs +++ /dev/null @@ -1,736 +0,0 @@ -//! Trait Resolution. See the [rustc guide] for more information on how this works. -//! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html - -pub mod query; -pub mod select; -pub mod specialization_graph; -mod structural_impls; - -use crate::mir::interpret::ErrorHandled; -use crate::ty::fold::{TypeFolder, TypeVisitor}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, AdtKind, List, Ty, TyCtxt}; - -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_span::{Span, DUMMY_SP}; -use syntax::ast; - -use std::fmt::Debug; -use std::rc::Rc; - -pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; - -pub use self::ObligationCauseCode::*; -pub use self::SelectionError::*; -pub use self::Vtable::*; - -/// Depending on the stage of compilation, we want projection to be -/// more or less conservative. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)] -pub enum Reveal { - /// At type-checking time, we refuse to project any associated - /// type that is marked `default`. Non-`default` ("final") types - /// are always projected. This is necessary in general for - /// soundness of specialization. However, we *could* allow - /// projections in fully-monomorphic cases. We choose not to, - /// because we prefer for `default type` to force the type - /// definition to be treated abstractly by any consumers of the - /// impl. Concretely, that means that the following example will - /// fail to compile: - /// - /// ``` - /// trait Assoc { - /// type Output; - /// } - /// - /// impl Assoc for T { - /// default type Output = bool; - /// } - /// - /// fn main() { - /// let <() as Assoc>::Output = true; - /// } - /// ``` - UserFacing, - - /// At codegen time, all monomorphic projections will succeed. - /// Also, `impl Trait` is normalized to the concrete type, - /// which has to be already collected by type-checking. - /// - /// NOTE: as `impl Trait`'s concrete type should *never* - /// be observable directly by the user, `Reveal::All` - /// should not be used by checks which may expose - /// type equality or type contents to the user. - /// There are some exceptions, e.g., around OIBITS and - /// transmute-checking, which expose some details, but - /// not the whole concrete type of the `impl Trait`. - All, -} - -/// The reason why we incurred this obligation; used for error reporting. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct ObligationCause<'tcx> { - pub span: Span, - - /// The ID of the fn body that triggered this obligation. This is - /// used for region obligations to determine the precise - /// environment in which the region obligation should be evaluated - /// (in particular, closures can add new assumptions). See the - /// field `region_obligations` of the `FulfillmentContext` for more - /// information. - pub body_id: hir::HirId, - - pub code: ObligationCauseCode<'tcx>, -} - -impl<'tcx> ObligationCause<'tcx> { - #[inline] - pub fn new( - span: Span, - body_id: hir::HirId, - code: ObligationCauseCode<'tcx>, - ) -> ObligationCause<'tcx> { - ObligationCause { span, body_id, code } - } - - pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> { - ObligationCause { span, body_id, code: MiscObligation } - } - - pub fn dummy() -> ObligationCause<'tcx> { - ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation } - } - - pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span { - match self.code { - ObligationCauseCode::CompareImplMethodObligation { .. } - | ObligationCauseCode::MainFunctionType - | ObligationCauseCode::StartFunctionType => tcx.sess.source_map().def_span(self.span), - ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - arm_span, - .. - }) => arm_span, - _ => self.span, - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum ObligationCauseCode<'tcx> { - /// Not well classified or should be obvious from the span. - MiscObligation, - - /// A slice or array is WF only if `T: Sized`. - SliceOrArrayElem, - - /// A tuple is WF only if its middle elements are `Sized`. - TupleElem, - - /// This is the trait reference from the given projection. - ProjectionWf(ty::ProjectionTy<'tcx>), - - /// In an impl of trait `X` for type `Y`, type `Y` must - /// also implement all supertraits of `X`. - ItemObligation(DefId), - - /// Like `ItemObligation`, but with extra detail on the source of the obligation. - BindingObligation(DefId, Span), - - /// A type like `&'a T` is WF only if `T: 'a`. - ReferenceOutlivesReferent(Ty<'tcx>), - - /// A type like `Box + 'b>` is WF only if `'b: 'a`. - ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>), - - /// Obligation incurred due to an object cast. - ObjectCastObligation(/* Object type */ Ty<'tcx>), - - /// Obligation incurred due to a coercion. - Coercion { - source: Ty<'tcx>, - target: Ty<'tcx>, - }, - - /// Various cases where expressions must be `Sized` / `Copy` / etc. - /// `L = X` implies that `L` is `Sized`. - AssignmentLhsSized, - /// `(x1, .., xn)` must be `Sized`. - TupleInitializerSized, - /// `S { ... }` must be `Sized`. - StructInitializerSized, - /// Type of each variable must be `Sized`. - VariableType(hir::HirId), - /// Argument type must be `Sized`. - SizedArgumentType, - /// Return type must be `Sized`. - SizedReturnType, - /// Yield type must be `Sized`. - SizedYieldType, - /// `[T, ..n]` implies that `T` must be `Copy`. - /// If `true`, suggest `const_in_array_repeat_expressions` feature flag. - RepeatVec(bool), - - /// Types of fields (other than the last, except for packed structs) in a struct must be sized. - FieldSized { - adt_kind: AdtKind, - last: bool, - }, - - /// Constant expressions must be sized. - ConstSized, - - /// `static` items must have `Sync` type. - SharedStatic, - - BuiltinDerivedObligation(DerivedObligationCause<'tcx>), - - ImplDerivedObligation(DerivedObligationCause<'tcx>), - - /// Error derived when matching traits/impls; see ObligationCause for more details - CompareImplMethodObligation { - item_name: ast::Name, - impl_item_def_id: DefId, - trait_item_def_id: DefId, - }, - - /// Error derived when matching traits/impls; see ObligationCause for more details - CompareImplTypeObligation { - item_name: ast::Name, - impl_item_def_id: DefId, - trait_item_def_id: DefId, - }, - - /// Checking that this expression can be assigned where it needs to be - // FIXME(eddyb) #11161 is the original Expr required? - ExprAssignable, - - /// Computing common supertype in the arms of a match expression - MatchExpressionArm(Box>), - - /// Type error arising from type checking a pattern against an expected type. - Pattern { - /// The span of the scrutinee or type expression which caused the `root_ty` type. - span: Option, - /// The root expected type induced by a scrutinee or type expression. - root_ty: Ty<'tcx>, - /// Whether the `Span` came from an expression or a type expression. - origin_expr: bool, - }, - - /// Constants in patterns must have `Structural` type. - ConstPatternStructural, - - /// Computing common supertype in an if expression - IfExpression(Box), - - /// Computing common supertype of an if expression with no else counter-part - IfExpressionWithNoElse, - - /// `main` has wrong type - MainFunctionType, - - /// `start` has wrong type - StartFunctionType, - - /// Intrinsic has wrong type - IntrinsicType, - - /// Method receiver - MethodReceiver, - - /// `return` with no expression - ReturnNoExpression, - - /// `return` with an expression - ReturnValue(hir::HirId), - - /// Return type of this function - ReturnType, - - /// Block implicit return - BlockTailExpression(hir::HirId), - - /// #[feature(trivial_bounds)] is not enabled - TrivialBound, - - AssocTypeBound(Box), -} - -impl ObligationCauseCode<'_> { - // Return the base obligation, ignoring derived obligations. - pub fn peel_derives(&self) -> &Self { - let mut base_cause = self; - while let BuiltinDerivedObligation(cause) | ImplDerivedObligation(cause) = base_cause { - base_cause = &cause.parent_code; - } - base_cause - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct AssocTypeBoundData { - pub impl_span: Option, - pub original: Span, - pub bounds: Vec, -} - -// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(target_arch = "x86_64")] -static_assert_size!(ObligationCauseCode<'_>, 32); - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct MatchExpressionArmCause<'tcx> { - pub arm_span: Span, - pub source: hir::MatchSource, - pub prior_arms: Vec, - pub last_ty: Ty<'tcx>, - pub scrut_hir_id: hir::HirId, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct IfExpressionCause { - pub then: Span, - pub outer: Option, - pub semicolon: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct DerivedObligationCause<'tcx> { - /// The trait reference of the parent obligation that led to the - /// current obligation. Note that only trait obligations lead to - /// derived obligations, so we just store the trait reference here - /// directly. - pub parent_trait_ref: ty::PolyTraitRef<'tcx>, - - /// The parent trait had this cause. - pub parent_code: Rc>, -} - -/// The following types: -/// * `WhereClause`, -/// * `WellFormed`, -/// * `FromEnv`, -/// * `DomainGoal`, -/// * `Goal`, -/// * `Clause`, -/// * `Environment`, -/// * `InEnvironment`, -/// are used for representing the trait system in the form of -/// logic programming clauses. They are part of the interface -/// for the chalk SLG solver. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum WhereClause<'tcx> { - Implemented(ty::TraitPredicate<'tcx>), - ProjectionEq(ty::ProjectionPredicate<'tcx>), - RegionOutlives(ty::RegionOutlivesPredicate<'tcx>), - TypeOutlives(ty::TypeOutlivesPredicate<'tcx>), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum WellFormed<'tcx> { - Trait(ty::TraitPredicate<'tcx>), - Ty(Ty<'tcx>), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum FromEnv<'tcx> { - Trait(ty::TraitPredicate<'tcx>), - Ty(Ty<'tcx>), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum DomainGoal<'tcx> { - Holds(WhereClause<'tcx>), - WellFormed(WellFormed<'tcx>), - FromEnv(FromEnv<'tcx>), - Normalize(ty::ProjectionPredicate<'tcx>), -} - -pub type PolyDomainGoal<'tcx> = ty::Binder>; - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)] -pub enum QuantifierKind { - Universal, - Existential, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)] -pub enum GoalKind<'tcx> { - Implies(Clauses<'tcx>, Goal<'tcx>), - And(Goal<'tcx>, Goal<'tcx>), - Not(Goal<'tcx>), - DomainGoal(DomainGoal<'tcx>), - Quantified(QuantifierKind, ty::Binder>), - Subtype(Ty<'tcx>, Ty<'tcx>), - CannotProve, -} - -pub type Goal<'tcx> = &'tcx GoalKind<'tcx>; - -pub type Goals<'tcx> = &'tcx List>; - -impl<'tcx> DomainGoal<'tcx> { - pub fn into_goal(self) -> GoalKind<'tcx> { - GoalKind::DomainGoal(self) - } - - pub fn into_program_clause(self) -> ProgramClause<'tcx> { - ProgramClause { - goal: self, - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::Other, - } - } -} - -impl<'tcx> GoalKind<'tcx> { - pub fn from_poly_domain_goal( - domain_goal: PolyDomainGoal<'tcx>, - tcx: TyCtxt<'tcx>, - ) -> GoalKind<'tcx> { - match domain_goal.no_bound_vars() { - Some(p) => p.into_goal(), - None => GoalKind::Quantified( - QuantifierKind::Universal, - domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())), - ), - } - } -} - -/// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary -/// Harrop Formulas". -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub enum Clause<'tcx> { - Implies(ProgramClause<'tcx>), - ForAll(ty::Binder>), -} - -impl Clause<'tcx> { - pub fn category(self) -> ProgramClauseCategory { - match self { - Clause::Implies(clause) => clause.category, - Clause::ForAll(clause) => clause.skip_binder().category, - } - } -} - -/// Multiple clauses. -pub type Clauses<'tcx> = &'tcx List>; - -/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying -/// that the domain goal `D` is true if `G1...Gn` are provable. This -/// is equivalent to the implication `G1..Gn => D`; we usually write -/// it with the reverse implication operator `:-` to emphasize the way -/// that programs are actually solved (via backchaining, which starts -/// with the goal to solve and proceeds from there). -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub struct ProgramClause<'tcx> { - /// This goal will be considered true ... - pub goal: DomainGoal<'tcx>, - - /// ... if we can prove these hypotheses (there may be no hypotheses at all): - pub hypotheses: Goals<'tcx>, - - /// Useful for filtering clauses. - pub category: ProgramClauseCategory, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)] -pub enum ProgramClauseCategory { - ImpliedBound, - WellFormed, - Other, -} - -/// A set of clauses that we assume to be true. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub struct Environment<'tcx> { - pub clauses: Clauses<'tcx>, -} - -impl Environment<'tcx> { - pub fn with(self, goal: G) -> InEnvironment<'tcx, G> { - InEnvironment { environment: self, goal } - } -} - -/// Something (usually a goal), along with an environment. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub struct InEnvironment<'tcx, G> { - pub environment: Environment<'tcx>, - pub goal: G, -} - -#[derive(Clone, Debug, TypeFoldable)] -pub enum SelectionError<'tcx> { - Unimplemented, - OutputTypeParameterMismatch( - ty::PolyTraitRef<'tcx>, - ty::PolyTraitRef<'tcx>, - ty::error::TypeError<'tcx>, - ), - TraitNotObjectSafe(DefId), - ConstEvalFailure(ErrorHandled), - Overflow, -} - -/// When performing resolution, it is typically the case that there -/// can be one of three outcomes: -/// -/// - `Ok(Some(r))`: success occurred with result `r` -/// - `Ok(None)`: could not definitely determine anything, usually due -/// to inconclusive type inference. -/// - `Err(e)`: error `e` occurred -pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; - -/// Given the successful resolution of an obligation, the `Vtable` -/// indicates where the vtable comes from. Note that while we call this -/// a "vtable", it does not necessarily indicate dynamic dispatch at -/// runtime. `Vtable` instances just tell the compiler where to find -/// methods, but in generic code those methods are typically statically -/// dispatched -- only when an object is constructed is a `Vtable` -/// instance reified into an actual vtable. -/// -/// For example, the vtable may be tied to a specific impl (case A), -/// or it may be relative to some bound that is in scope (case B). -/// -/// ``` -/// impl Clone for Option { ... } // Impl_1 -/// impl Clone for Box { ... } // Impl_2 -/// impl Clone for int { ... } // Impl_3 -/// -/// fn foo(concrete: Option>, -/// param: T, -/// mixed: Option) { -/// -/// // Case A: Vtable points at a specific impl. Only possible when -/// // type is concretely known. If the impl itself has bounded -/// // type parameters, Vtable will carry resolutions for those as well: -/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])]) -/// -/// // Case B: Vtable must be provided by caller. This applies when -/// // type is a type parameter. -/// param.clone(); // VtableParam -/// -/// // Case C: A mix of cases A and B. -/// mixed.clone(); // Vtable(Impl_1, [VtableParam]) -/// } -/// ``` -/// -/// ### The type parameter `N` -/// -/// See explanation on `VtableImplData`. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub enum Vtable<'tcx, N> { - /// Vtable identifying a particular impl. - VtableImpl(VtableImplData<'tcx, N>), - - /// Vtable for auto trait implementations. - /// This carries the information and nested obligations with regards - /// to an auto implementation for a trait `Trait`. The nested obligations - /// ensure the trait implementation holds for all the constituent types. - VtableAutoImpl(VtableAutoImplData), - - /// Successful resolution to an obligation provided by the caller - /// for some type parameter. The `Vec` represents the - /// obligations incurred from normalizing the where-clause (if - /// any). - VtableParam(Vec), - - /// Virtual calls through an object. - VtableObject(VtableObjectData<'tcx, N>), - - /// Successful resolution for a builtin trait. - VtableBuiltin(VtableBuiltinData), - - /// Vtable automatically generated for a closure. The `DefId` is the ID - /// of the closure expression. This is a `VtableImpl` in spirit, but the - /// impl is generated by the compiler and does not appear in the source. - VtableClosure(VtableClosureData<'tcx, N>), - - /// Same as above, but for a function pointer type with the given signature. - VtableFnPointer(VtableFnPointerData<'tcx, N>), - - /// Vtable automatically generated for a generator. - VtableGenerator(VtableGeneratorData<'tcx, N>), - - /// Vtable for a trait alias. - VtableTraitAlias(VtableTraitAliasData<'tcx, N>), -} - -impl<'tcx, N> Vtable<'tcx, N> { - pub fn nested_obligations(self) -> Vec { - match self { - VtableImpl(i) => i.nested, - VtableParam(n) => n, - VtableBuiltin(i) => i.nested, - VtableAutoImpl(d) => d.nested, - VtableClosure(c) => c.nested, - VtableGenerator(c) => c.nested, - VtableObject(d) => d.nested, - VtableFnPointer(d) => d.nested, - VtableTraitAlias(d) => d.nested, - } - } - - pub fn map(self, f: F) -> Vtable<'tcx, M> - where - F: FnMut(N) -> M, - { - match self { - VtableImpl(i) => VtableImpl(VtableImplData { - impl_def_id: i.impl_def_id, - substs: i.substs, - nested: i.nested.into_iter().map(f).collect(), - }), - VtableParam(n) => VtableParam(n.into_iter().map(f).collect()), - VtableBuiltin(i) => { - VtableBuiltin(VtableBuiltinData { nested: i.nested.into_iter().map(f).collect() }) - } - VtableObject(o) => VtableObject(VtableObjectData { - upcast_trait_ref: o.upcast_trait_ref, - vtable_base: o.vtable_base, - nested: o.nested.into_iter().map(f).collect(), - }), - VtableAutoImpl(d) => VtableAutoImpl(VtableAutoImplData { - trait_def_id: d.trait_def_id, - nested: d.nested.into_iter().map(f).collect(), - }), - VtableClosure(c) => VtableClosure(VtableClosureData { - closure_def_id: c.closure_def_id, - substs: c.substs, - nested: c.nested.into_iter().map(f).collect(), - }), - VtableGenerator(c) => VtableGenerator(VtableGeneratorData { - generator_def_id: c.generator_def_id, - substs: c.substs, - nested: c.nested.into_iter().map(f).collect(), - }), - VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData { - fn_ty: p.fn_ty, - nested: p.nested.into_iter().map(f).collect(), - }), - VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData { - alias_def_id: d.alias_def_id, - substs: d.substs, - nested: d.nested.into_iter().map(f).collect(), - }), - } - } -} - -/// Identifies a particular impl in the source, along with a set of -/// substitutions from the impl's type/lifetime parameters. The -/// `nested` vector corresponds to the nested obligations attached to -/// the impl's type parameters. -/// -/// The type parameter `N` indicates the type used for "nested -/// obligations" that are required by the impl. During type-check, this -/// is `Obligation`, as one might expect. During codegen, however, this -/// is `()`, because codegen only requires a shallow resolution of an -/// impl, and nested obligations are satisfied later. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableImplData<'tcx, N> { - pub impl_def_id: DefId, - pub substs: SubstsRef<'tcx>, - pub nested: Vec, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableGeneratorData<'tcx, N> { - pub generator_def_id: DefId, - pub substs: SubstsRef<'tcx>, - /// Nested obligations. This can be non-empty if the generator - /// signature contains associated types. - pub nested: Vec, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableClosureData<'tcx, N> { - pub closure_def_id: DefId, - pub substs: SubstsRef<'tcx>, - /// Nested obligations. This can be non-empty if the closure - /// signature contains associated types. - pub nested: Vec, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableAutoImplData { - pub trait_def_id: DefId, - pub nested: Vec, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableBuiltinData { - pub nested: Vec, -} - -/// A vtable for some object-safe trait `Foo` automatically derived -/// for the object type `Foo`. -#[derive(PartialEq, Eq, Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableObjectData<'tcx, N> { - /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. - pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, - - /// The vtable is formed by concatenating together the method lists of - /// the base object trait and all supertraits; this is the start of - /// `upcast_trait_ref`'s methods in that vtable. - pub vtable_base: usize, - - pub nested: Vec, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableFnPointerData<'tcx, N> { - pub fn_ty: Ty<'tcx>, - pub nested: Vec, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)] -pub struct VtableTraitAliasData<'tcx, N> { - pub alias_def_id: DefId, - pub substs: SubstsRef<'tcx>, - pub nested: Vec, -} - -pub trait ExClauseFold<'tcx> -where - Self: chalk_engine::context::Context + Clone, -{ - fn fold_ex_clause_with>( - ex_clause: &chalk_engine::ExClause, - folder: &mut F, - ) -> chalk_engine::ExClause; - - fn visit_ex_clause_with>( - ex_clause: &chalk_engine::ExClause, - visitor: &mut V, - ) -> bool; -} - -pub trait ChalkContextLift<'tcx> -where - Self: chalk_engine::context::Context + Clone, -{ - type LiftedExClause: Debug + 'tcx; - type LiftedDelayedLiteral: Debug + 'tcx; - type LiftedLiteral: Debug + 'tcx; - - fn lift_ex_clause_to_tcx( - ex_clause: &chalk_engine::ExClause, - tcx: TyCtxt<'tcx>, - ) -> Option; - - fn lift_delayed_literal_to_tcx( - ex_clause: &chalk_engine::DelayedLiteral, - tcx: TyCtxt<'tcx>, - ) -> Option; - - fn lift_literal_to_tcx( - ex_clause: &chalk_engine::Literal, - tcx: TyCtxt<'tcx>, - ) -> Option; -} diff --git a/src/librustc/traits/types/select.rs b/src/librustc/traits/types/select.rs deleted file mode 100644 index ac3d0049c0c..00000000000 --- a/src/librustc/traits/types/select.rs +++ /dev/null @@ -1,290 +0,0 @@ -//! Candidate selection. See the [rustc guide] for more information on how this works. -//! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html#selection - -use self::EvaluationResult::*; - -use super::{SelectionError, SelectionResult}; - -use crate::dep_graph::DepNodeIndex; -use crate::ty::{self, TyCtxt}; - -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::Lock; -use rustc_hir::def_id::DefId; - -#[derive(Clone, Default)] -pub struct SelectionCache<'tcx> { - pub hashmap: Lock< - FxHashMap< - ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>, - WithDepNode>>, - >, - >, -} - -impl<'tcx> SelectionCache<'tcx> { - /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear` - pub fn clear(&self) { - *self.hashmap.borrow_mut() = Default::default(); - } -} - -/// The selection process begins by considering all impls, where -/// clauses, and so forth that might resolve an obligation. Sometimes -/// we'll be able to say definitively that (e.g.) an impl does not -/// apply to the obligation: perhaps it is defined for `usize` but the -/// obligation is for `int`. In that case, we drop the impl out of the -/// list. But the other cases are considered *candidates*. -/// -/// For selection to succeed, there must be exactly one matching -/// candidate. If the obligation is fully known, this is guaranteed -/// by coherence. However, if the obligation contains type parameters -/// or variables, there may be multiple such impls. -/// -/// It is not a real problem if multiple matching impls exist because -/// of type variables - it just means the obligation isn't sufficiently -/// elaborated. In that case we report an ambiguity, and the caller can -/// try again after more type information has been gathered or report a -/// "type annotations needed" error. -/// -/// However, with type parameters, this can be a real problem - type -/// parameters don't unify with regular types, but they *can* unify -/// with variables from blanket impls, and (unless we know its bounds -/// will always be satisfied) picking the blanket impl will be wrong -/// for at least *some* substitutions. To make this concrete, if we have -/// -/// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; } -/// impl AsDebug for T { -/// type Out = T; -/// fn debug(self) -> fmt::Debug { self } -/// } -/// fn foo(t: T) { println!("{:?}", ::debug(t)); } -/// -/// we can't just use the impl to resolve the `` obligation -/// -- a type from another crate (that doesn't implement `fmt::Debug`) could -/// implement `AsDebug`. -/// -/// Because where-clauses match the type exactly, multiple clauses can -/// only match if there are unresolved variables, and we can mostly just -/// report this ambiguity in that case. This is still a problem - we can't -/// *do anything* with ambiguities that involve only regions. This is issue -/// #21974. -/// -/// If a single where-clause matches and there are no inference -/// variables left, then it definitely matches and we can just select -/// it. -/// -/// In fact, we even select the where-clause when the obligation contains -/// inference variables. The can lead to inference making "leaps of logic", -/// for example in this situation: -/// -/// pub trait Foo { fn foo(&self) -> T; } -/// impl Foo<()> for T { fn foo(&self) { } } -/// impl Foo for bool { fn foo(&self) -> bool { *self } } -/// -/// pub fn foo(t: T) where T: Foo { -/// println!("{:?}", >::foo(&t)); -/// } -/// fn main() { foo(false); } -/// -/// Here the obligation `>` can be matched by both the blanket -/// impl and the where-clause. We select the where-clause and unify `$0=bool`, -/// so the program prints "false". However, if the where-clause is omitted, -/// the blanket impl is selected, we unify `$0=()`, and the program prints -/// "()". -/// -/// Exactly the same issues apply to projection and object candidates, except -/// that we can have both a projection candidate and a where-clause candidate -/// for the same obligation. In that case either would do (except that -/// different "leaps of logic" would occur if inference variables are -/// present), and we just pick the where-clause. This is, for example, -/// required for associated types to work in default impls, as the bounds -/// are visible both as projection bounds and as where-clauses from the -/// parameter environment. -#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)] -pub enum SelectionCandidate<'tcx> { - BuiltinCandidate { - /// `false` if there are no *further* obligations. - has_nested: bool, - }, - ParamCandidate(ty::PolyTraitRef<'tcx>), - ImplCandidate(DefId), - AutoImplCandidate(DefId), - - /// This is a trait matching with a projected type as `Self`, and - /// we found an applicable bound in the trait definition. - ProjectionCandidate, - - /// Implementation of a `Fn`-family trait by one of the anonymous types - /// generated for a `||` expression. - ClosureCandidate, - - /// Implementation of a `Generator` trait by one of the anonymous types - /// generated for a generator. - GeneratorCandidate, - - /// Implementation of a `Fn`-family trait by one of the anonymous - /// types generated for a fn pointer type (e.g., `fn(int) -> int`) - FnPointerCandidate, - - TraitAliasCandidate(DefId), - - ObjectCandidate, - - BuiltinObjectCandidate, - - BuiltinUnsizeCandidate, -} - -/// The result of trait evaluation. The order is important -/// here as the evaluation of a list is the maximum of the -/// evaluations. -/// -/// The evaluation results are ordered: -/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions` -/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown` -/// - `EvaluatedToErr` implies `EvaluatedToRecur` -/// - the "union" of evaluation results is equal to their maximum - -/// all the "potential success" candidates can potentially succeed, -/// so they are noops when unioned with a definite error, and within -/// the categories it's easy to see that the unions are correct. -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)] -pub enum EvaluationResult { - /// Evaluation successful. - EvaluatedToOk, - /// Evaluation successful, but there were unevaluated region obligations. - EvaluatedToOkModuloRegions, - /// Evaluation is known to be ambiguous -- it *might* hold for some - /// assignment of inference variables, but it might not. - /// - /// While this has the same meaning as `EvaluatedToUnknown` -- we can't - /// know whether this obligation holds or not -- it is the result we - /// would get with an empty stack, and therefore is cacheable. - EvaluatedToAmbig, - /// Evaluation failed because of recursion involving inference - /// variables. We are somewhat imprecise there, so we don't actually - /// know the real result. - /// - /// This can't be trivially cached for the same reason as `EvaluatedToRecur`. - EvaluatedToUnknown, - /// Evaluation failed because we encountered an obligation we are already - /// trying to prove on this branch. - /// - /// We know this branch can't be a part of a minimal proof-tree for - /// the "root" of our cycle, because then we could cut out the recursion - /// and maintain a valid proof tree. However, this does not mean - /// that all the obligations on this branch do not hold -- it's possible - /// that we entered this branch "speculatively", and that there - /// might be some other way to prove this obligation that does not - /// go through this cycle -- so we can't cache this as a failure. - /// - /// For example, suppose we have this: - /// - /// ```rust,ignore (pseudo-Rust) - /// pub trait Trait { fn xyz(); } - /// // This impl is "useless", but we can still have - /// // an `impl Trait for SomeUnsizedType` somewhere. - /// impl Trait for T { fn xyz() {} } - /// - /// pub fn foo() { - /// ::xyz(); - /// } - /// ``` - /// - /// When checking `foo`, we have to prove `T: Trait`. This basically - /// translates into this: - /// - /// ```plain,ignore - /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait - /// ``` - /// - /// When we try to prove it, we first go the first option, which - /// recurses. This shows us that the impl is "useless" -- it won't - /// tell us that `T: Trait` unless it already implemented `Trait` - /// by some other means. However, that does not prevent `T: Trait` - /// does not hold, because of the bound (which can indeed be satisfied - /// by `SomeUnsizedType` from another crate). - // - // FIXME: when an `EvaluatedToRecur` goes past its parent root, we - // ought to convert it to an `EvaluatedToErr`, because we know - // there definitely isn't a proof tree for that obligation. Not - // doing so is still sound -- there isn't any proof tree, so the - // branch still can't be a part of a minimal one -- but does not re-enable caching. - EvaluatedToRecur, - /// Evaluation failed. - EvaluatedToErr, -} - -impl EvaluationResult { - /// Returns `true` if this evaluation result is known to apply, even - /// considering outlives constraints. - pub fn must_apply_considering_regions(self) -> bool { - self == EvaluatedToOk - } - - /// Returns `true` if this evaluation result is known to apply, ignoring - /// outlives constraints. - pub fn must_apply_modulo_regions(self) -> bool { - self <= EvaluatedToOkModuloRegions - } - - pub fn may_apply(self) -> bool { - match self { - EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => { - true - } - - EvaluatedToErr | EvaluatedToRecur => false, - } - } - - pub fn is_stack_dependent(self) -> bool { - match self { - EvaluatedToUnknown | EvaluatedToRecur => true, - - EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false, - } - } -} - -/// Indicates that trait evaluation caused overflow. -#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)] -pub struct OverflowError; - -impl<'tcx> From for SelectionError<'tcx> { - fn from(OverflowError: OverflowError) -> SelectionError<'tcx> { - SelectionError::Overflow - } -} - -#[derive(Clone, Default)] -pub struct EvaluationCache<'tcx> { - pub hashmap: Lock< - FxHashMap>, WithDepNode>, - >, -} - -impl<'tcx> EvaluationCache<'tcx> { - /// Actually frees the underlying memory in contrast to what stdlib containers do on `clear` - pub fn clear(&self) { - *self.hashmap.borrow_mut() = Default::default(); - } -} - -#[derive(Clone, Eq, PartialEq)] -pub struct WithDepNode { - dep_node: DepNodeIndex, - cached_value: T, -} - -impl WithDepNode { - pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self { - WithDepNode { dep_node, cached_value } - } - - pub fn get(&self, tcx: TyCtxt<'_>) -> T { - tcx.dep_graph.read_index(self.dep_node); - self.cached_value.clone() - } -} diff --git a/src/librustc/traits/types/structural_impls.rs b/src/librustc/traits/types/structural_impls.rs deleted file mode 100644 index 48ed29f2bb3..00000000000 --- a/src/librustc/traits/types/structural_impls.rs +++ /dev/null @@ -1,712 +0,0 @@ -use crate::traits; -use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::{self, Lift, Ty, TyCtxt}; -use rustc_span::symbol::Symbol; -use smallvec::SmallVec; - -use std::collections::{BTreeMap, BTreeSet}; -use std::fmt; -use std::rc::Rc; - -// Structural impls for the structs in `traits`. - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - super::VtableImpl(ref v) => write!(f, "{:?}", v), - - super::VtableAutoImpl(ref t) => write!(f, "{:?}", t), - - super::VtableClosure(ref d) => write!(f, "{:?}", d), - - super::VtableGenerator(ref d) => write!(f, "{:?}", d), - - super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d), - - super::VtableObject(ref d) => write!(f, "{:?}", d), - - super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n), - - super::VtableBuiltin(ref d) => write!(f, "{:?}", d), - - super::VtableTraitAlias(ref d) => write!(f, "{:?}", d), - } - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})", - self.impl_def_id, self.substs, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})", - self.generator_def_id, self.substs, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})", - self.closure_def_id, self.substs, self.nested - ) - } -} - -impl fmt::Debug for traits::VtableBuiltinData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "VtableBuiltinData(nested={:?})", self.nested) - } -} - -impl fmt::Debug for traits::VtableAutoImplData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableAutoImplData(trait_def_id={:?}, nested={:?})", - self.trait_def_id, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})", - self.upcast_trait_ref, self.vtable_base, self.nested - ) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "VtableFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested) - } -} - -impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})", - self.alias_def_id, self.substs, self.nested - ) - } -} - -impl<'tcx> fmt::Display for traits::WhereClause<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::WhereClause::*; - - // Bypass `ty::print` because it does not print out anonymous regions. - // FIXME(eddyb) implement a custom `PrettyPrinter`, or move this to `ty::print`. - fn write_region_name<'tcx>( - r: ty::Region<'tcx>, - fmt: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - match r { - ty::ReLateBound(index, br) => match br { - ty::BoundRegion::BrNamed(_, name) => write!(fmt, "{}", name), - ty::BoundRegion::BrAnon(var) => { - if *index == ty::INNERMOST { - write!(fmt, "'^{}", var) - } else { - write!(fmt, "'^{}_{}", index.index(), var) - } - } - _ => write!(fmt, "'_"), - }, - - _ => write!(fmt, "{}", r), - } - } - - match self { - Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref), - ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection), - RegionOutlives(predicate) => { - write!(fmt, "RegionOutlives({}: ", predicate.0)?; - write_region_name(predicate.1, fmt)?; - write!(fmt, ")") - } - TypeOutlives(predicate) => { - write!(fmt, "TypeOutlives({}: ", predicate.0)?; - write_region_name(predicate.1, fmt)?; - write!(fmt, ")") - } - } - } -} - -impl<'tcx> fmt::Display for traits::WellFormed<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::WellFormed::*; - - match self { - Trait(trait_ref) => write!(fmt, "WellFormed({})", trait_ref), - Ty(ty) => write!(fmt, "WellFormed({})", ty), - } - } -} - -impl<'tcx> fmt::Display for traits::FromEnv<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::FromEnv::*; - - match self { - Trait(trait_ref) => write!(fmt, "FromEnv({})", trait_ref), - Ty(ty) => write!(fmt, "FromEnv({})", ty), - } - } -} - -impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::DomainGoal::*; - - match self { - Holds(wc) => write!(fmt, "{}", wc), - WellFormed(wf) => write!(fmt, "{}", wf), - FromEnv(from_env) => write!(fmt, "{}", from_env), - Normalize(projection) => { - write!(fmt, "Normalize({} -> {})", projection.projection_ty, projection.ty) - } - } - } -} - -impl fmt::Display for traits::QuantifierKind { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::QuantifierKind::*; - - match self { - Universal => write!(fmt, "forall"), - Existential => write!(fmt, "exists"), - } - } -} - -/// Collect names for regions / types bound by a quantified goal / clause. -/// This collector does not try to do anything clever like in `ty::print`, it's just used -/// for debug output in tests anyway. -struct BoundNamesCollector { - // Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway. - regions: BTreeSet, - - // Sort by `BoundVar` index, so usually this should be equivalent to the order given - // by the list of type parameters. - types: BTreeMap, - - binder_index: ty::DebruijnIndex, -} - -impl BoundNamesCollector { - fn new() -> Self { - BoundNamesCollector { - regions: BTreeSet::new(), - types: BTreeMap::new(), - binder_index: ty::INNERMOST, - } - } - - fn is_empty(&self) -> bool { - self.regions.is_empty() && self.types.is_empty() - } - - fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut start = true; - for r in &self.regions { - if !start { - write!(fmt, ", ")?; - } - start = false; - write!(fmt, "{}", r)?; - } - for (_, t) in &self.types { - if !start { - write!(fmt, ", ")?; - } - start = false; - write!(fmt, "{}", t)?; - } - Ok(()) - } -} - -impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector { - fn visit_binder>(&mut self, t: &ty::Binder) -> bool { - self.binder_index.shift_in(1); - let result = t.super_visit_with(self); - self.binder_index.shift_out(1); - result - } - - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.kind { - ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { - self.types.insert( - bound_ty.var.as_u32(), - match bound_ty.kind { - ty::BoundTyKind::Param(name) => name, - ty::BoundTyKind::Anon => { - Symbol::intern(&format!("^{}", bound_ty.var.as_u32())) - } - }, - ); - } - - _ => (), - }; - - t.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - match r { - ty::ReLateBound(index, br) if *index == self.binder_index => match br { - ty::BoundRegion::BrNamed(_, name) => { - self.regions.insert(*name); - } - - ty::BoundRegion::BrAnon(var) => { - self.regions.insert(Symbol::intern(&format!("'^{}", var))); - } - - _ => (), - }, - - _ => (), - }; - - r.super_visit_with(self) - } -} - -impl<'tcx> fmt::Display for traits::Goal<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::GoalKind::*; - - match self { - Implies(hypotheses, goal) => { - write!(fmt, "if (")?; - for (index, hyp) in hypotheses.iter().enumerate() { - if index > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{}", hyp)?; - } - write!(fmt, ") {{ {} }}", goal) - } - And(goal1, goal2) => write!(fmt, "({} && {})", goal1, goal2), - Not(goal) => write!(fmt, "not {{ {} }}", goal), - DomainGoal(goal) => write!(fmt, "{}", goal), - Quantified(qkind, goal) => { - let mut collector = BoundNamesCollector::new(); - goal.skip_binder().visit_with(&mut collector); - - if !collector.is_empty() { - write!(fmt, "{}<", qkind)?; - collector.write_names(fmt)?; - write!(fmt, "> {{ ")?; - } - - write!(fmt, "{}", goal.skip_binder())?; - - if !collector.is_empty() { - write!(fmt, " }}")?; - } - - Ok(()) - } - Subtype(a, b) => write!(fmt, "{} <: {}", a, b), - CannotProve => write!(fmt, "CannotProve"), - } - } -} - -impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let traits::ProgramClause { goal, hypotheses, .. } = self; - write!(fmt, "{}", goal)?; - if !hypotheses.is_empty() { - write!(fmt, " :- ")?; - for (index, condition) in hypotheses.iter().enumerate() { - if index > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{}", condition)?; - } - } - write!(fmt, ".") - } -} - -impl<'tcx> fmt::Display for traits::Clause<'tcx> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - use crate::traits::Clause::*; - - match self { - Implies(clause) => write!(fmt, "{}", clause), - ForAll(clause) => { - let mut collector = BoundNamesCollector::new(); - clause.skip_binder().visit_with(&mut collector); - - if !collector.is_empty() { - write!(fmt, "forall<")?; - collector.write_names(fmt)?; - write!(fmt, "> {{ ")?; - } - - write!(fmt, "{}", clause.skip_binder())?; - - if !collector.is_empty() { - write!(fmt, " }}")?; - } - - Ok(()) - } - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Lift implementations - -impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> { - type Lifted = traits::SelectionError<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - match *self { - super::Unimplemented => Some(super::Unimplemented), - super::OutputTypeParameterMismatch(a, b, ref err) => { - tcx.lift(&(a, b)).and_then(|(a, b)| { - tcx.lift(err).map(|err| super::OutputTypeParameterMismatch(a, b, err)) - }) - } - super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)), - super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)), - super::Overflow => Some(super::Overflow), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { - type Lifted = traits::ObligationCauseCode<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - match *self { - super::ReturnNoExpression => Some(super::ReturnNoExpression), - super::MiscObligation => Some(super::MiscObligation), - super::SliceOrArrayElem => Some(super::SliceOrArrayElem), - super::TupleElem => Some(super::TupleElem), - super::ProjectionWf(proj) => tcx.lift(&proj).map(super::ProjectionWf), - super::ItemObligation(def_id) => Some(super::ItemObligation(def_id)), - super::BindingObligation(def_id, span) => Some(super::BindingObligation(def_id, span)), - super::ReferenceOutlivesReferent(ty) => { - tcx.lift(&ty).map(super::ReferenceOutlivesReferent) - } - super::ObjectTypeBound(ty, r) => tcx - .lift(&ty) - .and_then(|ty| tcx.lift(&r).and_then(|r| Some(super::ObjectTypeBound(ty, r)))), - super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation), - super::Coercion { source, target } => { - Some(super::Coercion { source: tcx.lift(&source)?, target: tcx.lift(&target)? }) - } - super::AssignmentLhsSized => Some(super::AssignmentLhsSized), - super::TupleInitializerSized => Some(super::TupleInitializerSized), - super::StructInitializerSized => Some(super::StructInitializerSized), - super::VariableType(id) => Some(super::VariableType(id)), - super::ReturnValue(id) => Some(super::ReturnValue(id)), - super::ReturnType => Some(super::ReturnType), - super::SizedArgumentType => Some(super::SizedArgumentType), - super::SizedReturnType => Some(super::SizedReturnType), - super::SizedYieldType => Some(super::SizedYieldType), - super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)), - super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }), - super::ConstSized => Some(super::ConstSized), - super::ConstPatternStructural => Some(super::ConstPatternStructural), - super::SharedStatic => Some(super::SharedStatic), - super::BuiltinDerivedObligation(ref cause) => { - tcx.lift(cause).map(super::BuiltinDerivedObligation) - } - super::ImplDerivedObligation(ref cause) => { - tcx.lift(cause).map(super::ImplDerivedObligation) - } - super::CompareImplMethodObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - } => Some(super::CompareImplMethodObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - }), - super::CompareImplTypeObligation { item_name, impl_item_def_id, trait_item_def_id } => { - Some(super::CompareImplTypeObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - }) - } - super::ExprAssignable => Some(super::ExprAssignable), - super::MatchExpressionArm(box super::MatchExpressionArmCause { - arm_span, - source, - ref prior_arms, - last_ty, - scrut_hir_id, - }) => tcx.lift(&last_ty).map(|last_ty| { - super::MatchExpressionArm(box super::MatchExpressionArmCause { - arm_span, - source, - prior_arms: prior_arms.clone(), - last_ty, - scrut_hir_id, - }) - }), - super::Pattern { span, root_ty, origin_expr } => { - tcx.lift(&root_ty).map(|root_ty| super::Pattern { span, root_ty, origin_expr }) - } - super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => { - Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon })) - } - super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse), - super::MainFunctionType => Some(super::MainFunctionType), - super::StartFunctionType => Some(super::StartFunctionType), - super::IntrinsicType => Some(super::IntrinsicType), - super::MethodReceiver => Some(super::MethodReceiver), - super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)), - super::TrivialBound => Some(super::TrivialBound), - super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> { - type Lifted = traits::DerivedObligationCause<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| { - tcx.lift(&*self.parent_code).map(|code| traits::DerivedObligationCause { - parent_trait_ref: trait_ref, - parent_code: Rc::new(code), - }) - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> { - type Lifted = traits::ObligationCause<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(&self.code).map(|code| traits::ObligationCause { - span: self.span, - body_id: self.body_id, - code, - }) - } -} - -// For codegen only. -impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { - type Lifted = traits::Vtable<'tcx, ()>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - match self.clone() { - traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) => { - tcx.lift(&substs).map(|substs| { - traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) - }) - } - traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)), - traits::VtableGenerator(traits::VtableGeneratorData { - generator_def_id, - substs, - nested, - }) => tcx.lift(&substs).map(|substs| { - traits::VtableGenerator(traits::VtableGeneratorData { - generator_def_id: generator_def_id, - substs: substs, - nested: nested, - }) - }), - traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested }) => { - tcx.lift(&substs).map(|substs| { - traits::VtableClosure(traits::VtableClosureData { - closure_def_id, - substs, - nested, - }) - }) - } - traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => { - tcx.lift(&fn_ty).map(|fn_ty| { - traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) - }) - } - traits::VtableParam(n) => Some(traits::VtableParam(n)), - traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)), - traits::VtableObject(traits::VtableObjectData { - upcast_trait_ref, - vtable_base, - nested, - }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| { - traits::VtableObject(traits::VtableObjectData { - upcast_trait_ref: trait_ref, - vtable_base, - nested, - }) - }), - traits::VtableTraitAlias(traits::VtableTraitAliasData { - alias_def_id, - substs, - nested, - }) => tcx.lift(&substs).map(|substs| { - traits::VtableTraitAlias(traits::VtableTraitAliasData { - alias_def_id, - substs, - nested, - }) - }), - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for traits::Environment<'a> { - type Lifted = traits::Environment<'tcx>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(&self.clauses).map(|clauses| traits::Environment { clauses }) - } -} - -impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> { - type Lifted = traits::InEnvironment<'tcx, G::Lifted>; - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(&self.environment).and_then(|environment| { - tcx.lift(&self.goal).map(|goal| traits::InEnvironment { environment, goal }) - }) - } -} - -impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause -where - C: chalk_engine::context::Context + Clone, - C: traits::ChalkContextLift<'tcx>, -{ - type Lifted = C::LiftedExClause; - - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - ::lift_ex_clause_to_tcx(self, tcx) - } -} - -impl<'tcx, C> Lift<'tcx> for chalk_engine::DelayedLiteral -where - C: chalk_engine::context::Context + Clone, - C: traits::ChalkContextLift<'tcx>, -{ - type Lifted = C::LiftedDelayedLiteral; - - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - ::lift_delayed_literal_to_tcx(self, tcx) - } -} - -impl<'tcx, C> Lift<'tcx> for chalk_engine::Literal -where - C: chalk_engine::context::Context + Clone, - C: traits::ChalkContextLift<'tcx>, -{ - type Lifted = C::LiftedLiteral; - - fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - ::lift_literal_to_tcx(self, tcx) - } -} - -/////////////////////////////////////////////////////////////////////////// -// TypeFoldable implementations. - -CloneTypeFoldableAndLiftImpls! { - traits::QuantifierKind, -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); - folder.tcx().intern_goals(&v) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = (**self).fold_with(folder); - folder.tcx().mk_goal(v) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - (**self).visit_with(visitor) - } -} - -CloneTypeFoldableAndLiftImpls! { - traits::ProgramClauseCategory, -} - -impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); - folder.tcx().intern_clauses(&v) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - -impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::ExClause -where - C: traits::ExClauseFold<'tcx>, - C::Substitution: Clone, - C::RegionConstraint: Clone, -{ - fn super_fold_with>(&self, folder: &mut F) -> Self { - ::fold_ex_clause_with(self, folder) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - ::visit_ex_clause_with(self, visitor) - } -} - -EnumTypeFoldableImpl! { - impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::DelayedLiteral { - (chalk_engine::DelayedLiteral::CannotProve)(a), - (chalk_engine::DelayedLiteral::Negative)(a), - (chalk_engine::DelayedLiteral::Positive)(a, b), - } where - C: chalk_engine::context::Context> + Clone, -} - -EnumTypeFoldableImpl! { - impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::Literal { - (chalk_engine::Literal::Negative)(a), - (chalk_engine::Literal::Positive)(a), - } where - C: chalk_engine::context::Context> + Clone, -} - -CloneTypeFoldableAndLiftImpls! { - chalk_engine::TableIndex, -} diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index f4006a1cd40..851bffc2065 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -122,7 +122,7 @@ impl<'tcx> OverloadedDeref<'tcx> { }; let method_def_id = tcx .associated_items(trait_def_id.unwrap()) - .iter() + .in_definition_order() .find(|m| m.kind == ty::AssocKind::Method) .unwrap() .def_id; diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs index 5ba3f80b822..31c106cb230 100644 --- a/src/librustc/ty/cast.rs +++ b/src/librustc/ty/cast.rs @@ -3,8 +3,8 @@ use crate::ty::{self, Ty}; +use rustc_ast::ast; use rustc_macros::HashStable; -use syntax::ast; /// Types that are represented as ints. #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index df1602b2ac4..c305999a64b 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -301,6 +301,7 @@ where macro_rules! __impl_decoder_methods { ($($name:ident -> $ty:ty;)*) => { $( + #[inline] fn $name(&mut self) -> Result<$ty, Self::Error> { self.opaque.$name() } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 00a9eee4bdc..325c4a5c89f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2,10 +2,11 @@ use crate::arena::Arena; use crate::dep_graph::DepGraph; -use crate::dep_graph::{self, DepConstructor, DepNode}; +use crate::dep_graph::{self, DepConstructor}; use crate::hir::exports::Export; use crate::hir::map as hir_map; -use crate::hir::map::DefPathHash; +use crate::hir::map::definitions::Definitions; +use crate::hir::map::{DefPathData, DefPathHash}; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; use crate::lint::{struct_lint_level, LintSource}; @@ -23,7 +24,6 @@ use crate::mir::{ use crate::sir::Sir; use crate::traits; use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals}; -use crate::ty::free_region_map::FreeRegionMap; use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx}; use crate::ty::query; use crate::ty::steal::Steal; @@ -43,6 +43,9 @@ use crate::ty::{InferConst, ParamConst}; use crate::ty::{List, TyKind, TyS}; use crate::util::common::ErrorReported; use rustc::lint::LintDiagnosticBuilder; +use rustc_ast::ast; +use rustc_ast::expand::allocator::AllocatorKind; +use rustc_ast::node_id::NodeMap; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::SelfProfilerRef; @@ -53,7 +56,7 @@ use rustc_data_structures::stable_hasher::{ use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; use rustc_hir::{HirId, Node, TraitCandidate}; use rustc_hir::{ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet}; use rustc_index::vec::{Idx, IndexVec}; @@ -66,9 +69,6 @@ use rustc_span::source_map::MultiSpan; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use rustc_target::spec::abi; -use syntax::ast; -use syntax::expand::allocator::AllocatorKind; -use syntax::node_id::NodeMap; use smallvec::SmallVec; use std::any::Any; @@ -206,13 +206,13 @@ fn validate_hir_id_for_typeck_tables( mut_access: bool, ) { if let Some(local_id_root) = local_id_root { - if hir_id.owner != local_id_root.index { + if hir_id.owner.to_def_id() != local_id_root { ty::tls::with(|tcx| { bug!( "node {} with HirId::owner {:?} cannot be placed in \ - TypeckTables with local_id_root {:?}", + TypeckTables with local_id_root {:?}", tcx.hir().node_to_string(hir_id), - DefId::local(hir_id.owner), + hir_id.owner, local_id_root ) }); @@ -416,11 +416,6 @@ pub struct TypeckTables<'tcx> { /// this field will be set to `true`. pub tainted_by_errors: bool, - /// Stores the free-region relationships that were deduced from - /// its where-clauses and parameter types. These are then - /// read-again by borrowck. - pub free_region_map: FreeRegionMap<'tcx>, - /// All the opaque types that are restricted to concrete types /// by this function. pub concrete_opaque_types: FxHashMap>, @@ -456,7 +451,6 @@ impl<'tcx> TypeckTables<'tcx> { coercion_casts: Default::default(), used_trait_imports: Lrc::new(Default::default()), tainted_by_errors: false, - free_region_map: Default::default(), concrete_opaque_types: Default::default(), upvar_list: Default::default(), generator_interior_types: Default::default(), @@ -612,7 +606,7 @@ impl<'tcx> TypeckTables<'tcx> { } match self.type_dependent_defs().get(expr.hir_id) { - Some(Ok((DefKind::Method, _))) => true, + Some(Ok((DefKind::AssocFn, _))) => true, _ => false, } } @@ -719,7 +713,6 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { ref used_trait_imports, tainted_by_errors, - ref free_region_map, ref concrete_opaque_types, ref upvar_list, ref generator_interior_types, @@ -740,10 +733,12 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { let local_id_root = local_id_root.expect("trying to hash invalid TypeckTables"); - let var_owner_def_id = - DefId { krate: local_id_root.krate, index: var_path.hir_id.owner }; + let var_owner_def_id = DefId { + krate: local_id_root.krate, + index: var_path.hir_id.owner.local_def_index, + }; let closure_def_id = - DefId { krate: local_id_root.krate, index: closure_expr_id.to_def_id().index }; + DefId { krate: local_id_root.krate, index: closure_expr_id.local_def_index }; ( hcx.def_path_hash(var_owner_def_id), var_path.hir_id.local_id, @@ -757,7 +752,6 @@ impl<'a, 'tcx> HashStable> for TypeckTables<'tcx> { coercion_casts.hash_stable(hcx, hasher); used_trait_imports.hash_stable(hcx, hasher); tainted_by_errors.hash_stable(hcx, hasher); - free_region_map.hash_stable(hcx, hasher); concrete_opaque_types.hash_stable(hcx, hasher); upvar_list.hash_stable(hcx, hasher); generator_interior_types.hash_stable(hcx, hasher); @@ -917,9 +911,9 @@ pub struct FreeRegionInfo { /// The central data structure of the compiler. It stores references /// to the various **arenas** and also houses the results of the /// various **compiler queries** that have been performed. See the -/// [rustc guide] for more details. +/// [rustc dev guide] for more details. /// -/// [rustc guide]: https://rust-lang.github.io/rustc-guide/ty.html +/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/ty.html #[derive(Copy, Clone)] #[rustc_diagnostic_item = "TyCtxt"] pub struct TyCtxt<'tcx> { @@ -939,7 +933,7 @@ pub struct GlobalCtxt<'tcx> { interners: CtxtInterners<'tcx>, - cstore: Box, + pub(crate) cstore: Box, pub sess: &'tcx Session, @@ -967,13 +961,13 @@ pub struct GlobalCtxt<'tcx> { /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. - trait_map: FxHashMap>>, + trait_map: FxHashMap>>, /// Export map produced by name resolution. export_map: FxHashMap>>, - /// This should usually be accessed with the `tcx.hir()` method. - pub(crate) hir_map: hir_map::Map<'tcx>, + pub(crate) untracked_crate: &'tcx hir::Crate<'tcx>, + pub(crate) definitions: &'tcx Definitions, /// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate /// as well as all upstream crates. Only populated in incremental mode. @@ -1120,7 +1114,9 @@ impl<'tcx> TyCtxt<'tcx> { extern_providers: ty::query::Providers<'tcx>, arena: &'tcx WorkerLocal>, resolutions: ty::ResolverOutputs, - hir: hir_map::Map<'tcx>, + krate: &'tcx hir::Crate<'tcx>, + definitions: &'tcx Definitions, + dep_graph: DepGraph, on_disk_query_result_cache: query::OnDiskCache<'tcx>, crate_name: &str, output_filenames: &OutputFilenames, @@ -1132,7 +1128,6 @@ impl<'tcx> TyCtxt<'tcx> { let common_types = CommonTypes::new(&interners); let common_lifetimes = CommonLifetimes::new(&interners); let common_consts = CommonConsts::new(&interners, &common_types); - let dep_graph = hir.dep_graph.clone(); let cstore = resolutions.cstore; let crates = cstore.crates_untracked(); let max_cnum = crates.iter().map(|c| c.as_usize()).max().unwrap_or(0); @@ -1143,7 +1138,7 @@ impl<'tcx> TyCtxt<'tcx> { let def_path_tables = crates .iter() .map(|&cnum| (cnum, cstore.def_path_table(cnum))) - .chain(iter::once((LOCAL_CRATE, hir.definitions().def_path_table()))); + .chain(iter::once((LOCAL_CRATE, definitions.def_path_table()))); // Precompute the capacity of the hashmap so we don't have to // re-allocate when populating it. @@ -1163,8 +1158,12 @@ impl<'tcx> TyCtxt<'tcx> { let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); for (k, v) in resolutions.trait_map { - let hir_id = hir.node_to_hir_id(k); + let hir_id = definitions.node_to_hir_id(k); let map = trait_map.entry(hir_id.owner).or_default(); + let v = v + .into_iter() + .map(|tc| tc.map_import_ids(|id| definitions.node_to_hir_id(id))) + .collect(); map.insert(hir_id.local_id, StableVec::new(v)); } @@ -1185,28 +1184,31 @@ impl<'tcx> TyCtxt<'tcx> { .export_map .into_iter() .map(|(k, v)| { - let exports: Vec<_> = - v.into_iter().map(|e| e.map_id(|id| hir.node_to_hir_id(id))).collect(); + let exports: Vec<_> = v + .into_iter() + .map(|e| e.map_id(|id| definitions.node_to_hir_id(id))) + .collect(); (k, exports) }) .collect(), maybe_unused_trait_imports: resolutions .maybe_unused_trait_imports .into_iter() - .map(|id| hir.local_def_id_from_node_id(id)) + .map(|id| definitions.local_def_id(id)) .collect(), maybe_unused_extern_crates: resolutions .maybe_unused_extern_crates .into_iter() - .map(|(id, sp)| (hir.local_def_id_from_node_id(id), sp)) + .map(|(id, sp)| (definitions.local_def_id(id), sp)) .collect(), glob_map: resolutions .glob_map .into_iter() - .map(|(id, names)| (hir.local_def_id_from_node_id(id), names)) + .map(|(id, names)| (definitions.local_def_id(id), names)) .collect(), extern_prelude: resolutions.extern_prelude, - hir_map: hir, + untracked_crate: krate, + definitions, def_path_hash_to_def_id, queries: query::Queries::new(providers, extern_providers, on_disk_query_result_cache), rcache: Default::default(), @@ -1266,7 +1268,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn def_key(self, id: DefId) -> hir_map::DefKey { - if id.is_local() { self.hir().def_key(id) } else { self.cstore.def_key(id) } + if let Some(id) = id.as_local() { self.hir().def_key(id) } else { self.cstore.def_key(id) } } /// Converts a `DefId` into its fully expanded `DefPath` (every @@ -1275,7 +1277,11 @@ impl<'tcx> TyCtxt<'tcx> { /// Note that if `id` is not local to this crate, the result will /// be a non-local `DefPath`. pub fn def_path(self, id: DefId) -> hir_map::DefPath { - if id.is_local() { self.hir().def_path(id) } else { self.cstore.def_path(id) } + if let Some(id) = id.as_local() { + self.hir().def_path(id) + } else { + self.cstore.def_path(id) + } } /// Returns whether or not the crate with CrateNum 'cnum' @@ -1286,8 +1292,8 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn def_path_hash(self, def_id: DefId) -> hir_map::DefPathHash { - if def_id.is_local() { - self.hir().definitions().def_path_hash(def_id.index) + if let Some(def_id) = def_id.as_local() { + self.definitions.def_path_hash(def_id) } else { self.cstore.def_path_hash(def_id) } @@ -1334,9 +1340,9 @@ impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> { - let krate = self.gcx.hir_map.untracked_krate(); + let krate = self.gcx.untracked_crate; - StableHashingContext::new(self.sess, krate, self.hir().definitions(), &*self.cstore) + StableHashingContext::new(self.sess, krate, self.definitions, &*self.cstore) } // This method makes sure that we have a DepNode and a Fingerprint for @@ -1348,7 +1354,7 @@ impl<'tcx> TyCtxt<'tcx> { // We cannot use the query versions of crates() and crate_hash(), since // those would need the DepNodes that we are allocating here. for cnum in self.cstore.crates_untracked() { - let dep_node = DepNode::new(self, DepConstructor::CrateMetadata(cnum)); + let dep_node = DepConstructor::CrateMetadata(self, cnum); let crate_hash = self.cstore.crate_hash_untracked(cnum); self.dep_graph.with_task( dep_node, @@ -1513,6 +1519,25 @@ impl<'tcx> TyCtxt<'tcx> { .subst(*self, self.mk_substs([self.lifetimes.re_static.into()].iter())), ) } + + /// Returns a displayable description and article for the given `def_id` (e.g. `("a", "struct")`). + pub fn article_and_description(&self, def_id: DefId) -> (&'static str, &'static str) { + self.def_kind(def_id) + .map(|def_kind| (def_kind.article(), def_kind.descr(def_id))) + .unwrap_or_else(|| match self.def_key(def_id).disambiguated_data.data { + DefPathData::ClosureExpr => match self.generator_kind(def_id) { + None => ("a", "closure"), + Some(rustc_hir::GeneratorKind::Async(..)) => ("an", "async closure"), + Some(rustc_hir::GeneratorKind::Gen) => ("a", "generator"), + }, + DefPathData::LifetimeNs(..) => ("a", "lifetime"), + DefPathData::Impl => ("an", "implementation"), + DefPathData::TypeNs(..) | DefPathData::ValueNs(..) | DefPathData::MacroNs(..) => { + unreachable!() + } + _ => bug!("article_and_description called on def_id {:?}", def_id), + }) + } } impl<'tcx> GlobalCtxt<'tcx> { @@ -1527,7 +1552,7 @@ impl<'tcx> GlobalCtxt<'tcx> { ty::tls::with_related_context(tcx, |icx| { let new_icx = ty::tls::ImplicitCtxt { tcx, - query: icx.query.clone(), + query: icx.query, diagnostics: icx.diagnostics, layout_depth: icx.layout_depth, task_deps: icx.task_deps, @@ -1613,7 +1638,7 @@ pub mod tls { use crate::dep_graph::TaskDeps; use crate::ty::query; - use rustc_data_structures::sync::{self, Lock, Lrc}; + use rustc_data_structures::sync::{self, Lock}; use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::OnDrop; use rustc_errors::Diagnostic; @@ -1638,7 +1663,7 @@ pub mod tls { /// The current query job, if any. This is updated by `JobOwner::start` in /// `ty::query::plumbing` when executing a query. - pub query: Option>>, + pub query: Option, /// Where to store diagnostics for the current query job, if any. /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. @@ -1689,6 +1714,7 @@ pub mod tls { /// Gets the pointer to the current `ImplicitCtxt`. #[cfg(not(parallel_compiler))] + #[inline] fn get_tlv() -> usize { TLV.with(|tlv| tlv.get()) } @@ -1702,7 +1728,7 @@ pub mod tls { set_tlv(context as *const _ as usize, || f(&context)) } - /// Enters `GlobalCtxt` by setting up libsyntax callbacks and + /// Enters `GlobalCtxt` by setting up librustc_ast callbacks and /// creating a initial `TyCtxt` and `ImplicitCtxt`. /// This happens once per rustc session and `TyCtxt`s only exists /// inside the `f` function. @@ -2238,22 +2264,22 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_mut_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ref(r, TypeAndMut { ty: ty, mutbl: hir::Mutability::Mut }) + self.mk_ref(r, TypeAndMut { ty, mutbl: hir::Mutability::Mut }) } #[inline] pub fn mk_imm_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ref(r, TypeAndMut { ty: ty, mutbl: hir::Mutability::Not }) + self.mk_ref(r, TypeAndMut { ty, mutbl: hir::Mutability::Not }) } #[inline] pub fn mk_mut_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ptr(TypeAndMut { ty: ty, mutbl: hir::Mutability::Mut }) + self.mk_ptr(TypeAndMut { ty, mutbl: hir::Mutability::Mut }) } #[inline] pub fn mk_imm_ptr(self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.mk_ptr(TypeAndMut { ty: ty, mutbl: hir::Mutability::Not }) + self.mk_ptr(TypeAndMut { ty, mutbl: hir::Mutability::Not }) } #[inline] @@ -2273,13 +2299,13 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> { - let kinds: Vec<_> = ts.into_iter().map(|&t| GenericArg::from(t)).collect(); + let kinds: Vec<_> = ts.iter().map(|&t| GenericArg::from(t)).collect(); self.mk_ty(Tuple(self.intern_substs(&kinds))) } pub fn mk_tup], Ty<'tcx>>>(self, iter: I) -> I::Output { iter.intern_with(|ts| { - let kinds: Vec<_> = ts.into_iter().map(|&t| GenericArg::from(t)).collect(); + let kinds: Vec<_> = ts.iter().map(|&t| GenericArg::from(t)).collect(); self.mk_ty(Tuple(self.intern_substs(&kinds))) }) } @@ -2375,7 +2401,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_ty_param(self, index: u32, name: Symbol) -> Ty<'tcx> { - self.mk_ty(Param(ParamTy { index, name: name })) + self.mk_ty(Param(ParamTy { index, name })) } #[inline] @@ -2455,7 +2481,7 @@ impl<'tcx> TyCtxt<'tcx> { // FIXME consider asking the input slice to be sorted to avoid // re-interning permutations, in which case that would be asserted // here. - if preds.len() == 0 { + if preds.is_empty() { // The macro-generated method below asserts we don't intern an empty slice. List::empty() } else { @@ -2464,31 +2490,31 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn intern_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx List> { - if ts.len() == 0 { List::empty() } else { self._intern_type_list(ts) } + if ts.is_empty() { List::empty() } else { self._intern_type_list(ts) } } pub fn intern_substs(self, ts: &[GenericArg<'tcx>]) -> &'tcx List> { - if ts.len() == 0 { List::empty() } else { self._intern_substs(ts) } + if ts.is_empty() { List::empty() } else { self._intern_substs(ts) } } pub fn intern_projs(self, ps: &[ProjectionKind]) -> &'tcx List { - if ps.len() == 0 { List::empty() } else { self._intern_projs(ps) } + if ps.is_empty() { List::empty() } else { self._intern_projs(ps) } } pub fn intern_place_elems(self, ts: &[PlaceElem<'tcx>]) -> &'tcx List> { - if ts.len() == 0 { List::empty() } else { self._intern_place_elems(ts) } + if ts.is_empty() { List::empty() } else { self._intern_place_elems(ts) } } pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'tcx> { - if ts.len() == 0 { List::empty() } else { self._intern_canonical_var_infos(ts) } + if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) } } pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> Clauses<'tcx> { - if ts.len() == 0 { List::empty() } else { self._intern_clauses(ts) } + if ts.is_empty() { List::empty() } else { self._intern_clauses(ts) } } pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> Goals<'tcx> { - if ts.len() == 0 { List::empty() } else { self._intern_goals(ts) } + if ts.is_empty() { List::empty() } else { self._intern_goals(ts) } } pub fn mk_fn_sig( @@ -2732,18 +2758,15 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { }; providers.lookup_stability = |tcx, id| { - assert_eq!(id.krate, LOCAL_CRATE); - let id = tcx.hir().definitions().def_index_to_hir_id(id.index); + let id = tcx.hir().local_def_id_to_hir_id(id.expect_local()); tcx.stability().local_stability(id) }; providers.lookup_const_stability = |tcx, id| { - assert_eq!(id.krate, LOCAL_CRATE); - let id = tcx.hir().definitions().def_index_to_hir_id(id.index); + let id = tcx.hir().local_def_id_to_hir_id(id.expect_local()); tcx.stability().local_const_stability(id) }; providers.lookup_deprecation_entry = |tcx, id| { - assert_eq!(id.krate, LOCAL_CRATE); - let id = tcx.hir().definitions().def_index_to_hir_id(id.index); + let id = tcx.hir().local_def_id_to_hir_id(id.expect_local()); tcx.stability().local_deprecation_entry(id) }; providers.extern_mod_stmt_cnum = |tcx, id| { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 6c5458e6e58..d0bc0d5fabf 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -1,10 +1,10 @@ use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt}; +use rustc_ast::ast; use rustc_errors::{pluralize, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_span::Span; use rustc_target::spec::abi; -use syntax::ast; use std::borrow::Cow; use std::fmt; @@ -341,7 +341,7 @@ impl<'tcx> TyCtxt<'tcx> { db.note("distinct uses of `impl Trait` result in different opaque types"); let e_str = values.expected.to_string(); let f_str = values.found.to_string(); - if &e_str == &f_str && &e_str == "impl std::future::Future" { + if e_str == f_str && &e_str == "impl std::future::Future" { // FIXME: use non-string based check. db.help( "if both `Future`s have the same `Output` type, consider \ diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 5aa8bd9df2a..2a937d6581d 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -1,11 +1,11 @@ use crate::ich::StableHashingContext; use crate::ty::{self, Ty, TyCtxt}; +use rustc_ast::ast; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::DefId; use std::fmt::Debug; use std::hash::Hash; use std::mem; -use syntax::ast; use self::SimplifiedTypeGen::*; diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 4a4280ba7dc..5243e1fbf57 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -80,13 +80,10 @@ impl FlagComputation { &ty::Error => self.add_flags(TypeFlags::HAS_TY_ERR), &ty::Param(_) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); - self.add_flags(TypeFlags::HAS_PARAMS); + self.add_flags(TypeFlags::HAS_TY_PARAM); } &ty::Generator(_, ref substs, _) => { - self.add_flags(TypeFlags::HAS_TY_CLOSURE); - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); self.add_substs(substs); } @@ -97,8 +94,6 @@ impl FlagComputation { } &ty::Closure(_, ref substs) => { - self.add_flags(TypeFlags::HAS_TY_CLOSURE); - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); self.add_substs(substs); } @@ -107,12 +102,10 @@ impl FlagComputation { } &ty::Placeholder(..) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); } &ty::Infer(infer) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right? self.add_flags(TypeFlags::HAS_TY_INFER); match infer { ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {} @@ -128,17 +121,17 @@ impl FlagComputation { } &ty::Projection(ref data) => { - self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_flags(TypeFlags::HAS_TY_PROJECTION); self.add_projection_ty(data); } &ty::UnnormalizedProjection(ref data) => { - self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_flags(TypeFlags::HAS_TY_PROJECTION); self.add_projection_ty(data); } &ty::Opaque(_, substs) => { - self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_flags(TypeFlags::HAS_TY_OPAQUE); self.add_substs(substs); } @@ -221,10 +214,10 @@ impl FlagComputation { match c.val { ty::ConstKind::Unevaluated(_, substs, _) => { self.add_substs(substs); - self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_flags(TypeFlags::HAS_CT_PROJECTION); } ty::ConstKind::Infer(infer) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES | TypeFlags::HAS_CT_INFER); + self.add_flags(TypeFlags::HAS_CT_INFER); match infer { InferConst::Fresh(_) => {} InferConst::Var(_) => self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX), @@ -232,11 +225,9 @@ impl FlagComputation { } ty::ConstKind::Bound(debruijn, _) => self.add_binder(debruijn), ty::ConstKind::Param(_) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); - self.add_flags(TypeFlags::HAS_PARAMS); + self.add_flags(TypeFlags::HAS_CT_PARAM); } ty::ConstKind::Placeholder(_) => { - self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); } ty::ConstKind::Value(_) => {} diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 1f007b970b0..4adca6c7d97 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -78,15 +78,21 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn has_projections(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PROJECTION) } + fn has_opaque_types(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) + } fn references_error(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_ERR) } fn has_param_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_PARAMS) + self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM) } fn has_infer_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_INFER) } + fn has_infer_types_or_consts(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER) + } fn has_infer_consts(&self) -> bool { self.has_type_flags(TypeFlags::HAS_CT_INFER) } @@ -94,9 +100,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.has_type_flags(TypeFlags::KEEP_IN_LOCAL_TCX) } fn needs_infer(&self) -> bool { - self.has_type_flags( - TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER | TypeFlags::HAS_CT_INFER, - ) + self.has_type_flags(TypeFlags::NEEDS_INFER) } fn has_placeholders(&self) -> bool { self.has_type_flags( @@ -111,15 +115,16 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn has_re_placeholders(&self) -> bool { self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER) } - fn has_closure_types(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_CLOSURE) - } /// "Free" regions in this context means that it has any region /// that is not (a) erased or (b) late-bound. fn has_free_regions(&self) -> bool { self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) } + fn has_erased_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_ERASED) + } + /// True if there are any un-erased free regions. fn has_erasable_regions(&self) -> bool { self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 144e3bc9c8b..b166c4dea0c 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -90,30 +90,46 @@ impl<'tcx> TyCtxt<'tcx> { /// ``` /// This code should only compile in modules where the uninhabitedness of Foo is /// visible. - pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool { + pub fn is_ty_uninhabited_from( + self, + module: DefId, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> bool { // To check whether this type is uninhabited at all (not just from the // given node), you could check whether the forest is empty. // ``` // forest.is_empty() // ``` - ty.uninhabited_from(self).contains(self, module) + ty.uninhabited_from(self, param_env).contains(self, module) } - pub fn is_ty_uninhabited_from_any_module(self, ty: Ty<'tcx>) -> bool { - !ty.uninhabited_from(self).is_empty() + pub fn is_ty_uninhabited_from_any_module( + self, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> bool { + !ty.uninhabited_from(self, param_env).is_empty() } } impl<'tcx> AdtDef { /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited. - fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>) -> DefIdForest { + fn uninhabited_from( + &self, + tcx: TyCtxt<'tcx>, + substs: SubstsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> DefIdForest { // Non-exhaustive ADTs from other crates are always considered inhabited. if self.is_variant_list_non_exhaustive() && !self.did.is_local() { DefIdForest::empty() } else { DefIdForest::intersection( tcx, - self.variants.iter().map(|v| v.uninhabited_from(tcx, substs, self.adt_kind())), + self.variants + .iter() + .map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)), ) } } @@ -126,6 +142,7 @@ impl<'tcx> VariantDef { tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, adt_kind: AdtKind, + param_env: ty::ParamEnv<'tcx>, ) -> DefIdForest { let is_enum = match adt_kind { // For now, `union`s are never considered uninhabited. @@ -140,7 +157,7 @@ impl<'tcx> VariantDef { } else { DefIdForest::union( tcx, - self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum)), + self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum, param_env)), ) } } @@ -153,8 +170,9 @@ impl<'tcx> FieldDef { tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, is_enum: bool, + param_env: ty::ParamEnv<'tcx>, ) -> DefIdForest { - let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx); + let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env); // FIXME(canndrew): Currently enum fields are (incorrectly) stored with // `Visibility::Invisible` so we need to override `self.vis` if we're // dealing with an enum. @@ -176,20 +194,21 @@ impl<'tcx> FieldDef { impl<'tcx> TyS<'tcx> { /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. - fn uninhabited_from(&self, tcx: TyCtxt<'tcx>) -> DefIdForest { + fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest { match self.kind { - Adt(def, substs) => def.uninhabited_from(tcx, substs), + Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env), Never => DefIdForest::full(tcx), - Tuple(ref tys) => { - DefIdForest::union(tcx, tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx))) - } + Tuple(ref tys) => DefIdForest::union( + tcx, + tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)), + ), - Array(ty, len) => match len.try_eval_usize(tcx, ty::ParamEnv::empty()) { + Array(ty, len) => match len.try_eval_usize(tcx, param_env) { // If the array is definitely non-empty, it's uninhabited if // the type of its elements is uninhabited. - Some(n) if n != 0 => ty.uninhabited_from(tcx), + Some(n) if n != 0 => ty.uninhabited_from(tcx, param_env), _ => DefIdForest::empty(), }, diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 335953fc41e..c9ad8707a74 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -1,12 +1,11 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::middle::lang_items::DropInPlaceFnLangItem; -use crate::traits; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable}; +use rustc_data_structures::AtomicRef; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_macros::HashStable; -use rustc_target::spec::abi::Abi; use std::fmt; @@ -40,6 +39,10 @@ pub enum InstanceDef<'tcx> { /// `::call_*` /// `DefId` is `FnTrait::call_*`. + /// + /// NB: the (`fn` pointer) type must currently be monomorphic to avoid double substitution + /// problems with the MIR shim bodies. `Instance::resolve` enforces this. + // FIXME(#69925) support polymorphic MIR shim bodies properly instead. FnPtrShim(DefId, Ty<'tcx>), /// `::fn`, "direct calls" of which are implicitly @@ -54,10 +57,21 @@ pub enum InstanceDef<'tcx> { call_once: DefId, }, - /// `drop_in_place::; None` for empty drop glue. + /// `core::ptr::drop_in_place::`. + /// The `DefId` is for `core::ptr::drop_in_place`. + /// The `Option>` is either `Some(T)`, or `None` for empty drop + /// glue. + /// + /// NB: the type must currently be monomorphic to avoid double substitution + /// problems with the MIR shim bodies. `Instance::resolve` enforces this. + // FIXME(#69925) support polymorphic MIR shim bodies properly instead. DropGlue(DefId, Option>), ///`::clone` shim. + /// + /// NB: the type must currently be monomorphic to avoid double substitution + /// problems with the MIR shim bodies. `Instance::resolve` enforces this. + // FIXME(#69925) support polymorphic MIR shim bodies properly instead. CloneShim(DefId, Ty<'tcx>), } @@ -113,9 +127,7 @@ impl<'tcx> Instance<'tcx> { } // If this a non-generic instance, it cannot be a shared monomorphization. - if self.substs.non_erasable_generics().next().is_none() { - return None; - } + self.substs.non_erasable_generics().next()?; match self.def { InstanceDef::Item(def_id) => tcx @@ -177,11 +189,25 @@ impl<'tcx> InstanceDef<'tcx> { if self.requires_inline(tcx) { return true; } - if let ty::InstanceDef::DropGlue(..) = *self { - // Drop glue wants to be instantiated at every codegen + if let ty::InstanceDef::DropGlue(.., Some(ty)) = *self { + // Drop glue generally wants to be instantiated at every codegen // unit, but without an #[inline] hint. We should make this // available to normal end-users. - return true; + if tcx.sess.opts.incremental.is_none() { + return true; + } + // When compiling with incremental, we can generate a *lot* of + // codegen units. Including drop glue into all of them has a + // considerable compile time cost. + // + // We include enums without destructors to allow, say, optimizing + // drops of `Option::None` before LTO. We also respect the intent of + // `#[inline]` on `Drop::drop` implementations. + return ty.ty_adt_def().map_or(true, |adt_def| { + adt_def.destructor(tcx).map_or(adt_def.is_enum(), |dtor| { + tcx.codegen_fn_attrs(dtor.did).requests_inline() + }) + }); } tcx.codegen_fn_attrs(self.def_id()).requests_inline() } @@ -227,7 +253,7 @@ impl<'tcx> Instance<'tcx> { def_id, substs ); - Instance { def: InstanceDef::Item(def_id), substs: substs } + Instance { def: InstanceDef::Item(def_id), substs } } pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { @@ -263,45 +289,7 @@ impl<'tcx> Instance<'tcx> { def_id: DefId, substs: SubstsRef<'tcx>, ) -> Option> { - debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); - let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { - debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env); - let item = tcx.associated_item(def_id); - resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) - } else { - let ty = tcx.type_of(def_id); - let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty); - - let def = match item_type.kind { - ty::FnDef(..) - if { - let f = item_type.fn_sig(tcx); - f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic - } => - { - debug!(" => intrinsic"); - ty::InstanceDef::Intrinsic(def_id) - } - _ => { - if Some(def_id) == tcx.lang_items().drop_in_place_fn() { - let ty = substs.type_at(0); - if ty.needs_drop(tcx, param_env.with_reveal_all()) { - debug!(" => nontrivial drop glue"); - ty::InstanceDef::DropGlue(def_id, Some(ty)) - } else { - debug!(" => trivial drop glue"); - ty::InstanceDef::DropGlue(def_id, None) - } - } else { - debug!(" => free item"); - ty::InstanceDef::Item(def_id) - } - } - }; - Some(Instance { def: def, substs: substs }) - }; - debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result); - result + (*RESOLVE_INSTANCE)(tcx, param_env, def_id, substs) } pub fn resolve_for_fn_ptr( @@ -336,7 +324,7 @@ impl<'tcx> Instance<'tcx> { ) -> Option> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); let fn_sig = tcx.fn_sig(def_id); - let is_vtable_shim = fn_sig.inputs().skip_binder().len() > 0 + let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty() && fn_sig.input(0).skip_binder().is_param(0) && tcx.generics_of(def_id).has_self; if is_vtable_shim { @@ -376,7 +364,7 @@ impl<'tcx> Instance<'tcx> { let fn_once = tcx.lang_items().fn_once_trait().unwrap(); let call_once = tcx .associated_items(fn_once) - .iter() + .in_definition_order() .find(|it| it.kind == ty::AssocKind::Method) .unwrap() .def_id; @@ -398,88 +386,6 @@ impl<'tcx> Instance<'tcx> { } } -fn resolve_associated_item<'tcx>( - tcx: TyCtxt<'tcx>, - trait_item: &ty::AssocItem, - param_env: ty::ParamEnv<'tcx>, - trait_id: DefId, - rcvr_substs: SubstsRef<'tcx>, -) -> Option> { - let def_id = trait_item.def_id; - debug!( - "resolve_associated_item(trait_item={:?}, \ - param_env={:?}, \ - trait_id={:?}, \ - rcvr_substs={:?})", - def_id, param_env, trait_id, rcvr_substs - ); - - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref))); - - // Now that we know which impl is being used, we can dispatch to - // the actual function: - match vtbl { - traits::VtableImpl(impl_data) => { - let (def_id, substs) = - traits::find_associated_item(tcx, param_env, trait_item, rcvr_substs, &impl_data); - - let resolved_item = tcx.associated_item(def_id); - - // Since this is a trait item, we need to see if the item is either a trait default item - // or a specialization because we can't resolve those unless we can `Reveal::All`. - // NOTE: This should be kept in sync with the similar code in - // `rustc::traits::project::assemble_candidates_from_impls()`. - let eligible = if !resolved_item.defaultness.is_default() { - true - } else if param_env.reveal == traits::Reveal::All { - !trait_ref.needs_subst() - } else { - false - }; - - if !eligible { - return None; - } - - let substs = tcx.erase_regions(&substs); - Some(ty::Instance::new(def_id, substs)) - } - traits::VtableGenerator(generator_data) => Some(Instance { - def: ty::InstanceDef::Item(generator_data.generator_def_id), - substs: generator_data.substs, - }), - traits::VtableClosure(closure_data) => { - let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); - Some(Instance::resolve_closure( - tcx, - closure_data.closure_def_id, - closure_data.substs, - trait_closure_kind, - )) - } - traits::VtableFnPointer(ref data) => Some(Instance { - def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), - substs: rcvr_substs, - }), - traits::VtableObject(ref data) => { - let index = traits::get_vtable_index_of_object_method(tcx, data, def_id); - Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }) - } - traits::VtableBuiltin(..) => { - if tcx.lang_items().clone_trait().is_some() { - Some(Instance { - def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()), - substs: rcvr_substs, - }) - } else { - None - } - } - traits::VtableAutoImpl(..) | traits::VtableParam(..) | traits::VtableTraitAlias(..) => None, - } -} - fn needs_fn_once_adapter_shim( actual_closure_kind: ty::ClosureKind, trait_closure_kind: ty::ClosureKind, @@ -512,3 +418,21 @@ fn needs_fn_once_adapter_shim( (ty::ClosureKind::FnMut, _) | (ty::ClosureKind::FnOnce, _) => Err(()), } } + +fn resolve_instance_default( + _tcx: TyCtxt<'tcx>, + _param_env: ty::ParamEnv<'tcx>, + _def_id: DefId, + _substs: SubstsRef<'tcx>, +) -> Option> { + unimplemented!() +} + +pub static RESOLVE_INSTANCE: AtomicRef< + for<'tcx> fn( + TyCtxt<'tcx>, + ty::ParamEnv<'tcx>, + DefId, + SubstsRef<'tcx>, + ) -> Option>, +> = AtomicRef::new(&(resolve_instance_default as _)); diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index e8bf2eb9a12..041dfc7d169 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1,31 +1,28 @@ -use crate::session::{self, DataTypeKind}; -use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable}; - -use rustc_attr as attr; -use rustc_span::DUMMY_SP; -use syntax::ast::{self, Ident, IntTy, UintTy}; - -use std::cmp; -use std::fmt; -use std::i128; -use std::iter; -use std::mem; -use std::ops::Bound; - use crate::ich::StableHashingContext; use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; use crate::ty::subst::Subst; +use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable}; + +use rustc_ast::ast::{self, Ident, IntTy, UintTy}; +use rustc_attr as attr; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; - +use rustc_session::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; +use rustc_span::DUMMY_SP; use rustc_target::abi::call::{ ArgAbi, ArgAttribute, ArgAttributes, Conv, FnAbi, PassMode, Reg, RegKind, }; pub use rustc_target::abi::*; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec}; +use std::cmp; +use std::fmt; +use std::iter; +use std::mem; +use std::ops::Bound; + pub trait IntegerExt { fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>; fn from_attr(cx: &C, ity: attr::IntType) -> Integer; @@ -502,7 +499,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let univariant = |fields: &[TyLayout<'_>], repr: &ReprOptions, kind| { Ok(tcx.intern_layout(self.univariant_uninterned(ty, fields, repr, kind)?)) }; - debug_assert!(!ty.has_infer_types()); + debug_assert!(!ty.has_infer_types_or_consts()); Ok(match ty.kind { // Basic scalars. @@ -798,7 +795,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // (Typechecking will reject discriminant-sizing attrs.) let v = present_first.unwrap(); - let kind = if def.is_enum() || variants[v].len() == 0 { + let kind = if def.is_enum() || variants[v].is_empty() { StructKind::AlwaysSized } else { let param_env = tcx.param_env(def.did); @@ -1001,7 +998,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } } - let (mut min, mut max) = (i128::max_value(), i128::min_value()); + let (mut min, mut max) = (i128::MAX, i128::MIN); let discr_type = def.repr.discr_type(); let bits = Integer::from_attr(self, discr_type).size().bits(); for (i, discr) in def.discriminants(tcx) { @@ -1021,7 +1018,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } } // We might have no inhabited variants, so pretend there's at least one. - if (min, max) == (i128::max_value(), i128::min_value()) { + if (min, max) == (i128::MAX, i128::MIN) { min = 0; max = 0; } @@ -1382,10 +1379,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Write down the order of our locals that will be promoted to the prefix. { - let mut idx = 0u32; - for local in ineligible_locals.iter() { - assignments[local] = Ineligible(Some(idx)); - idx += 1; + for (idx, local) in ineligible_locals.iter().enumerate() { + assignments[local] = Ineligible(Some(idx as u32)); } } debug!("generator saved local assignments: {:?}", assignments); @@ -1412,12 +1407,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // locals as part of the prefix. We compute the layout of all of // these fields at once to get optimal packing. let discr_index = substs.as_generator().prefix_tys(def_id, tcx).count(); - // FIXME(eddyb) set the correct vaidity range for the discriminant. - let discr_layout = self.layout_of(substs.as_generator().discr_ty(tcx))?; - let discr = match &discr_layout.abi { - Abi::Scalar(s) => s.clone(), - _ => bug!(), - }; + + // `info.variant_fields` already accounts for the reserved variants, so no need to add them. + let max_discr = (info.variant_fields.len() - 1) as u128; + let discr_int = Integer::fit_unsigned(max_discr); + let discr_int_ty = discr_int.to_ty(tcx, false); + let discr = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr }; + let discr_layout = self.tcx.intern_layout(LayoutDetails::scalar(self, discr.clone())); + let discr_layout = TyLayout { ty: discr_int_ty, details: discr_layout }; + let promoted_layouts = ineligible_locals .iter() .map(|local| subst_field(info.field_tys[local])) @@ -1651,7 +1649,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { if min_size < field_end { min_size = field_end; } - session::FieldInfo { + FieldInfo { name: name.to_string(), offset: offset.bytes(), size: field_layout.size.bytes(), @@ -1661,13 +1659,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }) .collect(); - session::VariantInfo { + VariantInfo { name: n.map(|n| n.to_string()), - kind: if layout.is_unsized() { - session::SizeKind::Min - } else { - session::SizeKind::Exact - }, + kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact }, align: layout.align.abi.bytes(), size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() }, fields: field_info, @@ -1752,7 +1746,7 @@ impl<'tcx> SizeSkeleton<'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Result, LayoutError<'tcx>> { - debug_assert!(!ty.has_infer_types()); + debug_assert!(!ty.has_infer_types_or_consts()); // First try computing a static layout. let err = match tcx.layout_of(param_env.and(ty)) { @@ -1907,36 +1901,6 @@ impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> { } } -pub trait MaybeResult { - type Error; - - fn from(x: Result) -> Self; - fn to_result(self) -> Result; -} - -impl MaybeResult for T { - type Error = !; - - fn from(x: Result) -> Self { - let Ok(x) = x; - x - } - fn to_result(self) -> Result { - Ok(self) - } -} - -impl MaybeResult for Result { - type Error = E; - - fn from(x: Result) -> Self { - x - } - fn to_result(self) -> Result { - self - } -} - pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>; impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> { @@ -2541,12 +2505,15 @@ where }; let target = &cx.tcx().sess.target.target; + let target_env_gnu_like = matches!(&target.target_env[..], "gnu" | "musl"); let win_x64_gnu = target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu"; - let linux_s390x = - target.target_os == "linux" && target.arch == "s390x" && target.target_env == "gnu"; - let linux_sparc64 = - target.target_os == "linux" && target.arch == "sparc64" && target.target_env == "gnu"; + let linux_s390x_gnu_like = + target.target_os == "linux" && target.arch == "s390x" && target_env_gnu_like; + let linux_sparc64_gnu_like = + target.target_os == "linux" && target.arch == "sparc64" && target_env_gnu_like; + let linux_powerpc_gnu_like = + target.target_os == "linux" && target.arch == "powerpc" && target_env_gnu_like; let rust_abi = match sig.abi { RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, _ => false, @@ -2579,7 +2546,7 @@ where if let Some(kind) = pointee.safe { attrs.pointee_align = Some(pointee.align); - // `Box` (`UniqueBorrowed`) are not necessarily dereferencable + // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable // for the entire duration of the function as they can be deallocated // any time. Set their valid size to 0. attrs.pointee_size = match kind { @@ -2617,9 +2584,14 @@ where if arg.layout.is_zst() { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. - // The same is true for s390x-unknown-linux-gnu - // and sparc64-unknown-linux-gnu. - if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { + // The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl}. + if is_return + || rust_abi + || (!win_x64_gnu + && !linux_s390x_gnu_like + && !linux_sparc64_gnu_like + && !linux_powerpc_gnu_like) + { arg.mode = PassMode::Ignore; } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2bda99e6d20..9e3853c51af 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -9,7 +9,6 @@ pub use self::Variance::*; use crate::arena::Arena; use crate::hir::exports::ExportMap; use crate::hir::map as hir_map; - use crate::ich::Fingerprint; use crate::ich::StableHashingContext; use crate::infer::canonical::Canonical; @@ -19,32 +18,33 @@ use crate::middle::resolve_lifetime::ObjectLifetimeDefault; use crate::mir::interpret::ErrorHandled; use crate::mir::GeneratorLayout; use crate::mir::ReadOnlyBodyAndCache; -use crate::session::DataTypeKind; use crate::traits::{self, Reveal}; use crate::ty; use crate::ty::layout::VariantIdx; use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; use crate::ty::util::{Discr, IntTypeExt}; use crate::ty::walk::TypeWalker; +use rustc_ast::ast::{self, Ident, Name}; +use rustc_ast::node_id::{NodeId, NodeMap, NodeSet}; use rustc_attr as attr; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{self, par_iter, Lrc, ParallelIterator}; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; +use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::{Constness, GlobMap, Node, TraitMap}; use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_serialize::{self, Encodable, Encoder}; +use rustc_session::DataTypeKind; use rustc_span::hygiene::ExpnId; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use rustc_target::abi::Align; -use syntax::ast::{self, Ident, Name}; -use syntax::node_id::{NodeId, NodeMap, NodeSet}; use std::cell::RefCell; use std::cmp::{self, Ordering}; @@ -83,6 +83,7 @@ pub use self::context::{ CtxtInterners, GeneratorInteriorTypeCause, GlobalCtxt, Lift, TypeckTables, }; +pub use self::instance::RESOLVE_INSTANCE; pub use self::instance::{Instance, InstanceDef}; pub use self::trait_def::TraitDef; @@ -126,7 +127,7 @@ pub struct ResolverOutputs { pub definitions: hir_map::Definitions, pub cstore: Box, pub extern_crate_map: NodeMap, - pub trait_map: TraitMap, + pub trait_map: TraitMap, pub maybe_unused_trait_imports: NodeSet, pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, pub export_map: ExportMap, @@ -215,13 +216,20 @@ impl AssocKind { ty::AssocKind::Const => "associated constant", } } + + pub fn namespace(&self) -> Namespace { + match *self { + ty::AssocKind::OpaqueTy | ty::AssocKind::Type => Namespace::TypeNS, + ty::AssocKind::Const | ty::AssocKind::Method => Namespace::ValueNS, + } + } } impl AssocItem { pub fn def_kind(&self) -> DefKind { match self.kind { AssocKind::Const => DefKind::AssocConst, - AssocKind::Method => DefKind::Method, + AssocKind::Method => DefKind::AssocFn, AssocKind::Type => DefKind::AssocTy, AssocKind::OpaqueTy => DefKind::AssocOpaqueTy, } @@ -256,6 +264,81 @@ impl AssocItem { } } +/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name. +/// +/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since +/// it is relatively expensive. Instead, items are indexed by `Symbol` and hygienic comparison is +/// done only on items with the same name. +#[derive(Debug, Clone, PartialEq, HashStable)] +pub struct AssociatedItems { + items: SortedIndexMultiMap, +} + +impl AssociatedItems { + /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order. + pub fn new(items_in_def_order: impl IntoIterator) -> Self { + let items = items_in_def_order.into_iter().map(|item| (item.ident.name, item)).collect(); + AssociatedItems { items } + } + + /// Returns a slice of associated items in the order they were defined. + /// + /// New code should avoid relying on definition order. If you need a particular associated item + /// for a known trait, make that trait a lang item instead of indexing this array. + pub fn in_definition_order(&self) -> impl '_ + Iterator { + self.items.iter().map(|(_, v)| v) + } + + /// Returns an iterator over all associated items with the given name, ignoring hygiene. + pub fn filter_by_name_unhygienic( + &self, + name: Symbol, + ) -> impl '_ + Iterator { + self.items.get_by_key(&name) + } + + /// Returns an iterator over all associated items with the given name. + /// + /// Multiple items may have the same name if they are in different `Namespace`s. For example, + /// an associated type can have the same name as a method. Use one of the `find_by_name_and_*` + /// methods below if you know which item you are looking for. + pub fn filter_by_name( + &'a self, + tcx: TyCtxt<'a>, + ident: Ident, + parent_def_id: DefId, + ) -> impl 'a + Iterator { + self.filter_by_name_unhygienic(ident.name) + .filter(move |item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) + } + + /// Returns the associated item with the given name and `AssocKind`, if one exists. + pub fn find_by_name_and_kind( + &self, + tcx: TyCtxt<'_>, + ident: Ident, + kind: AssocKind, + parent_def_id: DefId, + ) -> Option<&ty::AssocItem> { + self.filter_by_name_unhygienic(ident.name) + .filter(|item| item.kind == kind) + .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) + } + + /// Returns the associated item with the given name in the given `Namespace`, if one exists. + pub fn find_by_name_and_namespace( + &self, + tcx: TyCtxt<'_>, + ident: Ident, + ns: Namespace, + parent_def_id: DefId, + ) -> Option<&ty::AssocItem> { + self.filter_by_name_unhygienic(ident.name) + .filter(|item| item.kind.namespace() == ns) + .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id)) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable)] pub enum Visibility { /// Visible everywhere (including in other crates). @@ -286,7 +369,7 @@ pub trait DefIdTree: Copy { impl<'tcx> DefIdTree for TyCtxt<'tcx> { fn parent(self, id: DefId) -> Option { - self.def_key(id).parent.map(|index| DefId { index: index, ..id }) + self.def_key(id).parent.map(|index| DefId { index, ..id }) } } @@ -302,7 +385,7 @@ impl Visibility { def => Visibility::Restricted(def.def_id()), }, hir::VisibilityKind::Inherited => { - Visibility::Restricted(tcx.hir().get_module_parent(id)) + Visibility::Restricted(tcx.parent_module(id).to_def_id()) } } } @@ -433,72 +516,110 @@ pub struct CReaderCacheKey { pub pos: usize, } -// Flags that we track on types. These flags are propagated upwards -// through the type during type construction, so that we can quickly -// check whether the type has various kinds of types in it without -// recursing over the type itself. bitflags! { + /// Flags that we track on types. These flags are propagated upwards + /// through the type during type construction, so that we can quickly check + /// whether the type has various kinds of types in it without recursing + /// over the type itself. pub struct TypeFlags: u32 { - const HAS_PARAMS = 1 << 0; - const HAS_TY_INFER = 1 << 1; - const HAS_RE_INFER = 1 << 2; - const HAS_RE_PLACEHOLDER = 1 << 3; - - /// Does this have any `ReEarlyBound` regions? Used to - /// determine whether substitition is required, since those - /// represent regions that are bound in a `ty::Generics` and - /// hence may be substituted. - const HAS_RE_EARLY_BOUND = 1 << 4; - - /// Does this have any region that "appears free" in the type? - /// Basically anything but `ReLateBound` and `ReErased`. - const HAS_FREE_REGIONS = 1 << 5; - - /// Is an error type reachable? - const HAS_TY_ERR = 1 << 6; - const HAS_PROJECTION = 1 << 7; - - // FIXME: Rename this to the actual property since it's used for generators too - const HAS_TY_CLOSURE = 1 << 8; + // Does this have parameters? Used to determine whether substitution is + // required. + /// Does this have [Param]? + const HAS_TY_PARAM = 1 << 0; + /// Does this have [ReEarlyBound]? + const HAS_RE_PARAM = 1 << 1; + /// Does this have [ConstKind::Param]? + const HAS_CT_PARAM = 1 << 2; + + const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits + | TypeFlags::HAS_RE_PARAM.bits + | TypeFlags::HAS_CT_PARAM.bits; + + /// Does this have [Infer]? + const HAS_TY_INFER = 1 << 3; + /// Does this have [ReVar]? + const HAS_RE_INFER = 1 << 4; + /// Does this have [ConstKind::Infer]? + const HAS_CT_INFER = 1 << 5; + + /// Does this have inference variables? Used to determine whether + /// inference is required. + const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits + | TypeFlags::HAS_RE_INFER.bits + | TypeFlags::HAS_CT_INFER.bits; + + /// Does this have [Placeholder]? + const HAS_TY_PLACEHOLDER = 1 << 6; + /// Does this have [RePlaceholder]? + const HAS_RE_PLACEHOLDER = 1 << 7; + /// Does this have [ConstKind::Placeholder]? + const HAS_CT_PLACEHOLDER = 1 << 8; + + /// `true` if there are "names" of regions and so forth + /// that are local to a particular fn/inferctxt + const HAS_FREE_LOCAL_REGIONS = 1 << 9; /// `true` if there are "names" of types and regions and so forth /// that are local to a particular fn - const HAS_FREE_LOCAL_NAMES = 1 << 9; + const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits + | TypeFlags::HAS_CT_PARAM.bits + | TypeFlags::HAS_TY_INFER.bits + | TypeFlags::HAS_CT_INFER.bits + | TypeFlags::HAS_TY_PLACEHOLDER.bits + | TypeFlags::HAS_CT_PLACEHOLDER.bits + | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; + + /// Does this have [Projection] or [UnnormalizedProjection]? + const HAS_TY_PROJECTION = 1 << 10; + /// Does this have [Opaque]? + const HAS_TY_OPAQUE = 1 << 11; + /// Does this have [ConstKind::Unevaluated]? + const HAS_CT_PROJECTION = 1 << 12; + + /// Could this type be normalized further? + const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits + | TypeFlags::HAS_TY_OPAQUE.bits + | TypeFlags::HAS_CT_PROJECTION.bits; /// Present if the type belongs in a local type context. - /// Only set for Infer other than Fresh. - const KEEP_IN_LOCAL_TCX = 1 << 10; + /// Set for placeholders and inference variables that are not "Fresh". + const KEEP_IN_LOCAL_TCX = 1 << 13; - /// Does this have any `ReLateBound` regions? Used to check - /// if a global bound is safe to evaluate. - const HAS_RE_LATE_BOUND = 1 << 11; + /// Is an error type reachable? + const HAS_TY_ERR = 1 << 14; - const HAS_TY_PLACEHOLDER = 1 << 12; + /// Does this have any region that "appears free" in the type? + /// Basically anything but [ReLateBound] and [ReErased]. + const HAS_FREE_REGIONS = 1 << 15; - const HAS_CT_INFER = 1 << 13; - const HAS_CT_PLACEHOLDER = 1 << 14; + /// Does this have any [ReLateBound] regions? Used to check + /// if a global bound is safe to evaluate. + const HAS_RE_LATE_BOUND = 1 << 16; - const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | - TypeFlags::HAS_RE_EARLY_BOUND.bits; + /// Does this have any [ReErased] regions? + const HAS_RE_ERASED = 1 << 17; /// Flags representing the nominal content of a type, /// computed by FlagsComputation. If you add a new nominal /// flag, it should be added here too. - const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits | - TypeFlags::HAS_TY_INFER.bits | - TypeFlags::HAS_RE_INFER.bits | - TypeFlags::HAS_RE_PLACEHOLDER.bits | - TypeFlags::HAS_RE_EARLY_BOUND.bits | - TypeFlags::HAS_FREE_REGIONS.bits | - TypeFlags::HAS_TY_ERR.bits | - TypeFlags::HAS_PROJECTION.bits | - TypeFlags::HAS_TY_CLOSURE.bits | - TypeFlags::HAS_FREE_LOCAL_NAMES.bits | - TypeFlags::KEEP_IN_LOCAL_TCX.bits | - TypeFlags::HAS_RE_LATE_BOUND.bits | - TypeFlags::HAS_TY_PLACEHOLDER.bits | - TypeFlags::HAS_CT_INFER.bits | - TypeFlags::HAS_CT_PLACEHOLDER.bits; + const NOMINAL_FLAGS = TypeFlags::HAS_TY_PARAM.bits + | TypeFlags::HAS_RE_PARAM.bits + | TypeFlags::HAS_CT_PARAM.bits + | TypeFlags::HAS_TY_INFER.bits + | TypeFlags::HAS_RE_INFER.bits + | TypeFlags::HAS_CT_INFER.bits + | TypeFlags::HAS_TY_PLACEHOLDER.bits + | TypeFlags::HAS_RE_PLACEHOLDER.bits + | TypeFlags::HAS_CT_PLACEHOLDER.bits + | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits + | TypeFlags::HAS_TY_PROJECTION.bits + | TypeFlags::HAS_TY_OPAQUE.bits + | TypeFlags::HAS_CT_PROJECTION.bits + | TypeFlags::KEEP_IN_LOCAL_TCX.bits + | TypeFlags::HAS_TY_ERR.bits + | TypeFlags::HAS_FREE_REGIONS.bits + | TypeFlags::HAS_RE_LATE_BOUND.bits + | TypeFlags::HAS_RE_ERASED.bits; } } @@ -607,7 +728,7 @@ impl List { fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List { assert!(!mem::needs_drop::()); assert!(mem::size_of::() != 0); - assert!(slice.len() != 0); + assert!(!slice.is_empty()); // Align up the size of the len (usize) field let align = mem::align_of::(); @@ -840,7 +961,17 @@ pub enum GenericParamDefKind { Const, } -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +impl GenericParamDefKind { + pub fn descr(&self) -> &'static str { + match self { + GenericParamDefKind::Lifetime => "lifetime", + GenericParamDefKind::Type { .. } => "type", + GenericParamDefKind::Const => "constant", + } + } +} + +#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct GenericParamDef { pub name: Symbol, pub def_id: DefId, @@ -1356,7 +1487,7 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> { fn to_predicate(&self) -> Predicate<'tcx> { ty::Predicate::Trait( - ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }), + ty::Binder::dummy(ty::TraitPredicate { trait_ref: *self.value }), self.constness, ) } @@ -1570,7 +1701,7 @@ rustc_index::newtype_index! { } impl UniverseIndex { - pub const ROOT: UniverseIndex = UniverseIndex::from_u32_const(0); + pub const ROOT: UniverseIndex = UniverseIndex::from_u32(0); /// Returns the "next" universe index in order -- this new index /// is considered to extend all previous universes. This @@ -1717,10 +1848,10 @@ impl<'tcx> ParamEnv<'tcx> { Reveal::UserFacing => ParamEnvAnd { param_env: self, value }, Reveal::All => { - if value.has_placeholders() || value.needs_infer() || value.has_param_types() { - ParamEnvAnd { param_env: self, value } - } else { + if value.is_global() { ParamEnvAnd { param_env: self.without_caller_bounds(), value } + } else { + ParamEnvAnd { param_env: self, value } } } } @@ -2100,7 +2231,7 @@ impl ReprOptions { if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.def_path_str(did))) { flags.insert(ReprFlags::IS_LINEAR); } - ReprOptions { int: size, align: max_align, pack: min_pack, flags: flags } + ReprOptions { int: size, align: max_align, pack: min_pack, flags } } #[inline] @@ -2380,10 +2511,10 @@ impl<'tcx> AdtDef { let repr_type = self.repr.discr_type(); match tcx.const_eval_poly(expr_did) { Ok(val) => { - // FIXME: Find the right type and use it instead of `val.ty` here - if let Some(b) = val.try_eval_bits(tcx, param_env, val.ty) { + let ty = repr_type.to_ty(tcx); + if let Some(b) = val.try_to_bits_for_ty(tcx, param_env, ty) { trace!("discriminants: {} ({:?})", b, repr_type); - Some(Discr { val: b, ty: val.ty }) + Some(Discr { val: b, ty }) } else { info!("invalid enum discriminant: {:#?}", val); crate::mir::interpret::struct_error( @@ -2723,14 +2854,14 @@ impl<'tcx> TyCtxt<'tcx> { .for_each(|&body_id| f(self.hir().body_owner_def_id(body_id))); } - pub fn provided_trait_methods(self, id: DefId) -> impl Iterator { + pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator { self.associated_items(id) - .iter() + .in_definition_order() .filter(|item| item.kind == AssocKind::Method && item.defaultness.has_value()) } pub fn trait_relevant_for_never(self, did: DefId) -> bool { - self.associated_items(did).iter().any(|item| item.relevant_for_never()) + self.associated_items(did).in_definition_order().any(|item| item.relevant_for_never()) } pub fn opt_item_name(self, def_id: DefId) -> Option { @@ -2745,7 +2876,7 @@ impl<'tcx> TyCtxt<'tcx> { } } else { match self.def_kind(def_id).expect("no def for `DefId`") { - DefKind::AssocConst | DefKind::Method | DefKind::AssocTy => true, + DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy => true, _ => false, } }; @@ -2924,7 +3055,7 @@ impl<'tcx> TyCtxt<'tcx> { /// `DefId` of the impl that the method belongs to; otherwise, returns `None`. pub fn impl_of_method(self, def_id: DefId) -> Option { let item = if def_id.krate != LOCAL_CRATE { - if let Some(DefKind::Method) = self.def_kind(def_id) { + if let Some(DefKind::AssocFn) = self.def_kind(def_id) { Some(self.associated_item(def_id)) } else { None @@ -2956,7 +3087,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn hygienic_eq(self, use_name: Ident, def_name: Ident, def_parent_def_id: DefId) -> bool { // We could use `Ident::eq` here, but we deliberately don't. The name // comparison fails frequently, and we want to avoid the expensive - // `modern()` calls required for the span comparison whenever possible. + // `normalize_to_macros_2_0()` calls required for the span comparison whenever possible. use_name.name == def_name.name && use_name .span @@ -2965,14 +3096,14 @@ impl<'tcx> TyCtxt<'tcx> { } fn expansion_that_defined(self, scope: DefId) -> ExpnId { - match scope.krate { - LOCAL_CRATE => self.hir().definitions().expansion_that_defined(scope.index), - _ => ExpnId::root(), + match scope.as_local() { + Some(scope) => self.hir().definitions().expansion_that_defined(scope), + None => ExpnId::root(), } } pub fn adjust_ident(self, mut ident: Ident, scope: DefId) -> Ident { - ident.span.modernize_and_adjust(self.expansion_that_defined(scope)); + ident.span.normalize_to_macros_2_0_and_adjust(self.expansion_that_defined(scope)); ident } @@ -2982,14 +3113,20 @@ impl<'tcx> TyCtxt<'tcx> { scope: DefId, block: hir::HirId, ) -> (Ident, DefId) { - let scope = match ident.span.modernize_and_adjust(self.expansion_that_defined(scope)) { - Some(actual_expansion) => { - self.hir().definitions().parent_module_of_macro_def(actual_expansion) - } - None => self.hir().get_module_parent(block), - }; + let scope = + match ident.span.normalize_to_macros_2_0_and_adjust(self.expansion_that_defined(scope)) + { + Some(actual_expansion) => { + self.hir().definitions().parent_module_of_macro_def(actual_expansion) + } + None => self.parent_module(block).to_def_id(), + }; (ident, scope) } + + pub fn is_object_safe(self, key: DefId) -> bool { + self.object_safety_violations(key).is_empty() + } } #[derive(Clone, HashStable)] @@ -3011,8 +3148,11 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { context::provide(providers); erase_regions::provide(providers); layout::provide(providers); - *providers = - ty::query::Providers { trait_impls_of: trait_def::trait_impls_of_provider, ..*providers }; + *providers = ty::query::Providers { + trait_impls_of: trait_def::trait_impls_of_provider, + all_local_trait_impls: trait_def::all_local_trait_impls, + ..*providers + }; } /// A map for the local crate mapping each type to a vector of its diff --git a/src/librustc/ty/normalize_erasing_regions.rs b/src/librustc/ty/normalize_erasing_regions.rs index dc64482907f..cbaabd8e1f1 100644 --- a/src/librustc/ty/normalize_erasing_regions.rs +++ b/src/librustc/ty/normalize_erasing_regions.rs @@ -34,10 +34,7 @@ impl<'tcx> TyCtxt<'tcx> { if !value.has_projections() { value } else { - value.fold_with(&mut NormalizeAfterErasingRegionsFolder { - tcx: self, - param_env: param_env, - }) + value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env }) } } diff --git a/src/librustc/ty/print/mod.rs b/src/librustc/ty/print/mod.rs index 3ade9661917..8d784833bd3 100644 --- a/src/librustc/ty/print/mod.rs +++ b/src/librustc/ty/print/mod.rs @@ -97,7 +97,7 @@ pub trait Printer<'tcx>: Sized { args: &[GenericArg<'tcx>], ) -> Result; - // Defaults (should not be overriden): + // Defaults (should not be overridden): fn default_print_def_path( self, diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 38442295636..cb01d821c18 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1,7 +1,7 @@ use crate::hir::map::{DefPathData, DisambiguatedDefPathData}; use crate::middle::cstore::{ExternCrate, ExternCrateSource}; use crate::middle::region; -use crate::mir::interpret::{sign_extend, truncate, ConstValue, Scalar}; +use crate::mir::interpret::{sign_extend, truncate, AllocId, ConstValue, Pointer, Scalar}; use crate::ty::layout::{Integer, IntegerExt, Size}; use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable}; @@ -11,12 +11,13 @@ use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; +use rustc_ast::ast; use rustc_attr::{SignedInt, UnsignedInt}; use rustc_span::symbol::{kw, Symbol}; use rustc_target::spec::abi::Abi; -use syntax::ast; use std::cell::Cell; +use std::char; use std::collections::BTreeMap; use std::fmt::{self, Write as _}; use std::ops::{Deref, DerefMut}; @@ -64,8 +65,7 @@ thread_local! { /// calling the same query. pub fn with_no_queries R, R>(f: F) -> R { NO_QUERIES.with(|no_queries| { - let old = no_queries.get(); - no_queries.set(true); + let old = no_queries.replace(true); let result = f(); no_queries.set(old); result @@ -78,8 +78,7 @@ pub fn with_no_queries R, R>(f: F) -> R { /// so this variable disables that check. pub fn with_forced_impl_filename_line R, R>(f: F) -> R { FORCE_IMPL_FILENAME_LINE.with(|force| { - let old = force.get(); - force.set(true); + let old = force.replace(true); let result = f(); force.set(old); result @@ -89,8 +88,7 @@ pub fn with_forced_impl_filename_line R, R>(f: F) -> R { /// Adds the `crate::` prefix to paths where appropriate. pub fn with_crate_prefix R, R>(f: F) -> R { SHOULD_PREFIX_WITH_CRATE.with(|flag| { - let old = flag.get(); - flag.set(true); + let old = flag.replace(true); let result = f(); flag.set(old); result @@ -139,7 +137,7 @@ impl RegionHighlightMode { pub fn highlighting_region(&mut self, region: ty::Region<'_>, number: usize) { let num_slots = self.highlight_regions.len(); let first_avail_slot = - self.highlight_regions.iter_mut().filter(|s| s.is_none()).next().unwrap_or_else(|| { + self.highlight_regions.iter_mut().find(|s| s.is_none()).unwrap_or_else(|| { bug!("can only highlight {} placeholders at a time", num_slots,) }); *first_avail_slot = Some((*region, number)); @@ -213,6 +211,21 @@ pub trait PrettyPrinter<'tcx>: Ok(self) } + /// Prints `{f: t}` or `{f as t}` depending on the `cast` argument + fn typed_value( + mut self, + f: impl FnOnce(Self) -> Result, + t: impl FnOnce(Self) -> Result, + conversion: &str, + ) -> Result { + self.write_str("{")?; + self = f(self)?; + self.write_str(conversion)?; + self = t(self)?; + self.write_str("}")?; + Ok(self) + } + /// Prints `<...>` around what `f` prints. fn generic_delimiters( self, @@ -224,7 +237,7 @@ pub trait PrettyPrinter<'tcx>: /// This is typically the case for all non-`'_` regions. fn region_should_not_be_omitted(&self, region: ty::Region<'_>) -> bool; - // Defaults (should not be overriden): + // Defaults (should not be overridden): /// If possible, this returns a global path resolving to `def_id` that is visible /// from at least one local module, and returns `true`. If the crate defining `def_id` is @@ -239,7 +252,7 @@ pub trait PrettyPrinter<'tcx>: /// post-process it into the valid and visible version that /// accounts for re-exports. /// - /// This method should only be callled by itself or + /// This method should only be called by itself or /// `try_print_visible_def_path`. /// /// `callers` is a chain of visible_parent's leading to `def_id`, @@ -520,14 +533,7 @@ pub trait PrettyPrinter<'tcx>: ty::Error => p!(write("[type error]")), ty::Param(ref param_ty) => p!(write("{}", param_ty)), ty::Bound(debruijn, bound_ty) => match bound_ty.kind { - ty::BoundTyKind::Anon => { - if debruijn == ty::INNERMOST { - p!(write("^{}", bound_ty.var.index())) - } else { - p!(write("^{}_{}", debruijn.index(), bound_ty.var.index())) - } - } - + ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?, ty::BoundTyKind::Param(p) => p!(write("{}", p)), }, ty::Adt(def, substs) => { @@ -688,11 +694,11 @@ pub trait PrettyPrinter<'tcx>: if self.tcx().sess.verbose() { p!(write("{:?}", sz)); } else if let ty::ConstKind::Unevaluated(..) = sz.val { - // do not try to evalute unevaluated constants. If we are const evaluating an + // do not try to evaluate unevaluated constants. If we are const evaluating an // array length anon const, rustc will (with debug assertions) print the // constant's path. Which will end up here again. p!(write("_")); - } else if let Some(n) = sz.try_eval_usize(self.tcx(), ty::ParamEnv::empty()) { + } else if let Some(n) = sz.val.try_to_bits(self.tcx().data_layout.pointer_size) { p!(write("{}", n)); } else { p!(write("_")); @@ -705,6 +711,18 @@ pub trait PrettyPrinter<'tcx>: Ok(self) } + fn pretty_print_bound_var( + &mut self, + debruijn: ty::DebruijnIndex, + var: ty::BoundVar, + ) -> Result<(), Self::Error> { + if debruijn == ty::INNERMOST { + write!(self, "^{}", var.index()) + } else { + write!(self, "^{}_{}", debruijn.index(), var.index()) + } + } + fn infer_ty_name(&self, _: ty::TyVid) -> Option { None } @@ -845,16 +863,23 @@ pub trait PrettyPrinter<'tcx>: macro_rules! print_underscore { () => {{ - p!(write("_")); if print_ty { - p!(write(": "), print(ct.ty)); + self = self.typed_value( + |mut this| { + write!(this, "_")?; + Ok(this) + }, + |this| this.print_type(ct.ty), + ": ", + )?; + } else { + write!(self, "_")?; } }}; } - match (ct.val, &ct.ty.kind) { - (_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)), - (ty::ConstKind::Unevaluated(did, substs, promoted), _) => { + match ct.val { + ty::ConstKind::Unevaluated(did, substs, promoted) => { if let Some(promoted) = promoted { p!(print_value_path(did, substs)); p!(write("::{:?}", promoted)); @@ -879,143 +904,265 @@ pub trait PrettyPrinter<'tcx>: } } } - (ty::ConstKind::Infer(..), _) => print_underscore!(), - (ty::ConstKind::Param(ParamConst { name, .. }), _) => p!(write("{}", name)), - (ty::ConstKind::Value(value), _) => { + ty::ConstKind::Infer(..) => print_underscore!(), + ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)), + ty::ConstKind::Value(value) => { return self.pretty_print_const_value(value, ct.ty, print_ty); } - _ => { - // fallback - p!(write("{:?}", ct.val)); - if print_ty { - p!(write(": "), print(ct.ty)); - } + ty::ConstKind::Bound(debruijn, bound_var) => { + self.pretty_print_bound_var(debruijn, bound_var)? } + ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)), }; Ok(self) } - fn pretty_print_const_value( + fn pretty_print_const_scalar( mut self, - ct: ConstValue<'tcx>, + scalar: Scalar, ty: Ty<'tcx>, print_ty: bool, ) -> Result { define_scoped_cx!(self); - if self.tcx().sess.verbose() { - p!(write("ConstValue({:?}: {:?})", ct, ty)); - return Ok(self); - } - - let u8 = self.tcx().types.u8; - - match (ct, &ty.kind) { - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Bool) => { - p!(write("{}", if data == 0 { "false" } else { "true" })) - } - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F32)) => { + match (scalar, &ty.kind) { + // Byte strings (&[u8; N]) + ( + Scalar::Ptr(ptr), + ty::Ref( + _, + ty::TyS { + kind: + ty::Array( + ty::TyS { kind: ty::Uint(ast::UintTy::U8), .. }, + ty::Const { + val: + ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { + data, + .. + })), + .. + }, + ), + .. + }, + _, + ), + ) => { + let byte_str = self + .tcx() + .alloc_map + .lock() + .unwrap_memory(ptr.alloc_id) + .get_bytes(&self.tcx(), ptr, Size::from_bytes(*data as u64)) + .unwrap(); + p!(pretty_print_byte_str(byte_str)); + } + // Bool + (Scalar::Raw { data: 0, .. }, ty::Bool) => p!(write("false")), + (Scalar::Raw { data: 1, .. }, ty::Bool) => p!(write("true")), + // Float + (Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F32)) => { p!(write("{}f32", Single::from_bits(data))) } - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F64)) => { + (Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F64)) => { p!(write("{}f64", Double::from_bits(data))) } - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Uint(ui)) => { + // Int + (Scalar::Raw { data, .. }, ty::Uint(ui)) => { let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size(); - let max = truncate(u128::max_value(), bit_size); + let max = truncate(u128::MAX, bit_size); let ui_str = ui.name_str(); if data == max { p!(write("std::{}::MAX", ui_str)) } else { - p!(write("{}{}", data, ui_str)) + if print_ty { p!(write("{}{}", data, ui_str)) } else { p!(write("{}", data)) } }; } - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Int(i)) => { - let bit_size = Integer::from_attr(&self.tcx(), SignedInt(*i)).size().bits() as u128; + (Scalar::Raw { data, .. }, ty::Int(i)) => { + let size = Integer::from_attr(&self.tcx(), SignedInt(*i)).size(); + let bit_size = size.bits() as u128; let min = 1u128 << (bit_size - 1); let max = min - 1; - let ty = self.tcx().lift(&ty).unwrap(); - let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; let i_str = i.name_str(); match data { d if d == min => p!(write("std::{}::MIN", i_str)), d if d == max => p!(write("std::{}::MAX", i_str)), - _ => p!(write("{}{}", sign_extend(data, size) as i128, i_str)), + _ => { + let data = sign_extend(data, size) as i128; + if print_ty { + p!(write("{}{}", data, i_str)) + } else { + p!(write("{}", data)) + } + } } } - (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) => { - p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap())) - } - (ConstValue::Scalar(_), ty::RawPtr(_)) => p!(write("{{pointer}}")), - (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::FnPtr(_)) => { + // Char + (Scalar::Raw { data, .. }, ty::Char) if char::from_u32(data as u32).is_some() => { + p!(write("{:?}", char::from_u32(data as u32).unwrap())) + } + // Raw pointers + (Scalar::Raw { data, .. }, ty::RawPtr(_)) => { + self = self.typed_value( + |mut this| { + write!(this, "0x{:x}", data)?; + Ok(this) + }, + |this| this.print_type(ty), + " as ", + )?; + } + (Scalar::Ptr(ptr), ty::FnPtr(_)) => { let instance = { let alloc_map = self.tcx().alloc_map.lock(); alloc_map.unwrap_fn(ptr.alloc_id) }; - p!(print_value_path(instance.def_id(), instance.substs)); - } - _ => { - let printed = if let ty::Ref(_, ref_ty, _) = ty.kind { - let byte_str = match (ct, &ref_ty.kind) { - (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => { - let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty()); - Some( - self.tcx() - .alloc_map - .lock() - .unwrap_memory(ptr.alloc_id) - .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)) - .unwrap(), - ) - } - (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { - // The `inspect` here is okay since we checked the bounds, and there are - // no relocations (we have an active slice reference here). We don't use - // this result to affect interpreter execution. - Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end)) - } - _ => None, - }; - - if let Some(byte_str) = byte_str { - p!(write("b\"")); - for &c in byte_str { - for e in std::ascii::escape_default(c) { - self.write_char(e as char)?; - } - } - p!(write("\"")); - true - } else if let (ConstValue::Slice { data, start, end }, ty::Str) = - (ct, &ref_ty.kind) - { - // The `inspect` here is okay since we checked the bounds, and there are no - // relocations (we have an active `str` reference here). We don't use this - // result to affect interpreter execution. - let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end); - let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); - p!(write("{:?}", s)); - true + self = self.typed_value( + |this| this.print_value_path(instance.def_id(), instance.substs), + |this| this.print_type(ty), + " as ", + )?; + } + // For function type zsts just printing the path is enough + (Scalar::Raw { size: 0, .. }, ty::FnDef(d, s)) => p!(print_value_path(*d, s)), + // Empty tuples are frequently occurring, so don't print the fallback. + (Scalar::Raw { size: 0, .. }, ty::Tuple(ts)) if ts.is_empty() => p!(write("()")), + // Zero element arrays have a trivial representation. + ( + Scalar::Raw { size: 0, .. }, + ty::Array( + _, + ty::Const { + val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: 0, .. })), + .. + }, + ), + ) => p!(write("[]")), + // Nontrivial types with scalar bit representation + (Scalar::Raw { data, size }, _) => { + let print = |mut this: Self| { + if size == 0 { + write!(this, "transmute(())")?; } else { - false + write!(this, "transmute(0x{:01$x})", data, size as usize * 2)?; } + Ok(this) + }; + self = if print_ty { + self.typed_value(print, |this| this.print_type(ty), ": ")? } else { - false + print(self)? }; - if !printed { - // fallback - p!(write("{:?}", ct)); - if print_ty { - p!(write(": "), print(ty)); - } - } } - }; + // Any pointer values not covered by a branch above + (Scalar::Ptr(p), _) => { + self = self.pretty_print_const_pointer(p, ty, print_ty)?; + } + } Ok(self) } + + /// This is overridden for MIR printing because we only want to hide alloc ids from users, not + /// from MIR where it is actually useful. + fn pretty_print_const_pointer( + mut self, + _: Pointer, + ty: Ty<'tcx>, + print_ty: bool, + ) -> Result { + if print_ty { + self.typed_value( + |mut this| { + this.write_str("&_")?; + Ok(this) + }, + |this| this.print_type(ty), + ": ", + ) + } else { + self.write_str("&_")?; + Ok(self) + } + } + + fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result { + define_scoped_cx!(self); + p!(write("b\"")); + for &c in byte_str { + for e in std::ascii::escape_default(c) { + self.write_char(e as char)?; + } + } + p!(write("\"")); + Ok(self) + } + + fn pretty_print_const_value( + mut self, + ct: ConstValue<'tcx>, + ty: Ty<'tcx>, + print_ty: bool, + ) -> Result { + define_scoped_cx!(self); + + if self.tcx().sess.verbose() { + p!(write("ConstValue({:?}: {:?})", ct, ty)); + return Ok(self); + } + + let u8_type = self.tcx().types.u8; + + match (ct, &ty.kind) { + (ConstValue::Scalar(scalar), _) => self.pretty_print_const_scalar(scalar, ty, print_ty), + ( + ConstValue::Slice { data, start, end }, + ty::Ref(_, ty::TyS { kind: ty::Slice(t), .. }, _), + ) if *t == u8_type => { + // The `inspect` here is okay since we checked the bounds, and there are + // no relocations (we have an active slice reference here). We don't use + // this result to affect interpreter execution. + let byte_str = data.inspect_with_undef_and_ptr_outside_interpreter(start..end); + self.pretty_print_byte_str(byte_str) + } + ( + ConstValue::Slice { data, start, end }, + ty::Ref(_, ty::TyS { kind: ty::Str, .. }, _), + ) => { + // The `inspect` here is okay since we checked the bounds, and there are no + // relocations (we have an active `str` reference here). We don't use this + // result to affect interpreter execution. + let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end); + let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); + p!(write("{:?}", s)); + Ok(self) + } + (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => { + let n = n.val.try_to_bits(self.tcx().data_layout.pointer_size).unwrap(); + // cast is ok because we already checked for pointer size (32 or 64 bit) above + let n = Size::from_bytes(n as u64); + let ptr = Pointer::new(AllocId(0), offset); + + let byte_str = alloc.get_bytes(&self.tcx(), ptr, n).unwrap(); + p!(write("*")); + p!(pretty_print_byte_str(byte_str)); + Ok(self) + } + // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading + // their fields instead of just dumping the memory. + _ => { + // fallback + p!(write("{:?}", ct)); + if print_ty { + p!(write(": "), print(ty)); + } + Ok(self) + } + } + } } // HACK(eddyb) boxed to avoid moving around a large struct by-value. @@ -1027,6 +1174,7 @@ pub struct FmtPrinterData<'a, 'tcx, F> { empty_path: bool, in_value: bool, + pub print_alloc_ids: bool, used_region_names: FxHashSet, region_index: usize, @@ -1057,6 +1205,7 @@ impl FmtPrinter<'a, 'tcx, F> { fmt, empty_path: false, in_value: ns == Namespace::ValueNS, + print_alloc_ids: false, used_region_names: Default::default(), region_index: 0, binder_depth: 0, @@ -1329,6 +1478,22 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { self.pretty_in_binder(value) } + fn typed_value( + mut self, + f: impl FnOnce(Self) -> Result, + t: impl FnOnce(Self) -> Result, + conversion: &str, + ) -> Result { + self.write_str("{")?; + self = f(self)?; + self.write_str(conversion)?; + let was_in_value = std::mem::replace(&mut self.in_value, false); + self = t(self)?; + self.in_value = was_in_value; + self.write_str("}")?; + Ok(self) + } + fn generic_delimiters( mut self, f: impl FnOnce(Self) -> Result, @@ -1385,6 +1550,28 @@ impl PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { ty::ReStatic | ty::ReEmpty(_) | ty::ReClosureBound(_) => true, } } + + fn pretty_print_const_pointer( + self, + p: Pointer, + ty: Ty<'tcx>, + print_ty: bool, + ) -> Result { + let print = |mut this: Self| { + define_scoped_cx!(this); + if this.print_alloc_ids { + p!(write("{:?}", p)); + } else { + p!(write("&_")); + } + Ok(this) + }; + if print_ty { + self.typed_value(print, |this| this.print_type(ty), ": ") + } else { + print(self) + } + } } // HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`. diff --git a/src/librustc/ty/query/README.md b/src/librustc/ty/query/README.md index 4b5e08cecd9..8ec07b9fdeb 100644 --- a/src/librustc/ty/query/README.md +++ b/src/librustc/ty/query/README.md @@ -1,3 +1,3 @@ -For more information about how the query system works, see the [rustc guide]. +For more information about how the query system works, see the [rustc dev guide]. -[rustc guide]: https://rust-lang.github.io/rustc-guide/query.html +[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/query.html diff --git a/src/librustc/ty/query/caches.rs b/src/librustc/ty/query/caches.rs new file mode 100644 index 00000000000..efc2804bd4d --- /dev/null +++ b/src/librustc/ty/query/caches.rs @@ -0,0 +1,112 @@ +use crate::dep_graph::DepNodeIndex; +use crate::ty::query::config::QueryAccessors; +use crate::ty::query::plumbing::{QueryLookup, QueryState, QueryStateShard}; +use crate::ty::TyCtxt; + +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sharded::Sharded; +use std::default::Default; +use std::hash::Hash; + +pub(crate) trait CacheSelector { + type Cache: QueryCache; +} + +pub(crate) trait QueryCache: Default { + type Sharded: Default; + + /// Checks if the query is already computed and in the cache. + /// It returns the shard index and a lock guard to the shard, + /// which will be used if the query is not in the cache and we need + /// to compute it. + fn lookup<'tcx, R, GetCache, OnHit, OnMiss, Q>( + &self, + state: &'tcx QueryState<'tcx, Q>, + get_cache: GetCache, + key: K, + // `on_hit` can be called while holding a lock to the query state shard. + on_hit: OnHit, + on_miss: OnMiss, + ) -> R + where + Q: QueryAccessors<'tcx>, + GetCache: for<'a> Fn(&'a mut QueryStateShard<'tcx, Q>) -> &'a mut Self::Sharded, + OnHit: FnOnce(&V, DepNodeIndex) -> R, + OnMiss: FnOnce(K, QueryLookup<'tcx, Q>) -> R; + + fn complete( + &self, + tcx: TyCtxt<'tcx>, + lock_sharded_storage: &mut Self::Sharded, + key: K, + value: V, + index: DepNodeIndex, + ); + + fn iter( + &self, + shards: &Sharded, + get_shard: impl Fn(&mut L) -> &mut Self::Sharded, + f: impl for<'a> FnOnce(Box + 'a>) -> R, + ) -> R; +} + +pub struct DefaultCacheSelector; + +impl CacheSelector for DefaultCacheSelector { + type Cache = DefaultCache; +} + +#[derive(Default)] +pub struct DefaultCache; + +impl QueryCache for DefaultCache { + type Sharded = FxHashMap; + + #[inline(always)] + fn lookup<'tcx, R, GetCache, OnHit, OnMiss, Q>( + &self, + state: &'tcx QueryState<'tcx, Q>, + get_cache: GetCache, + key: K, + on_hit: OnHit, + on_miss: OnMiss, + ) -> R + where + Q: QueryAccessors<'tcx>, + GetCache: for<'a> Fn(&'a mut QueryStateShard<'tcx, Q>) -> &'a mut Self::Sharded, + OnHit: FnOnce(&V, DepNodeIndex) -> R, + OnMiss: FnOnce(K, QueryLookup<'tcx, Q>) -> R, + { + let mut lookup = state.get_lookup(&key); + let lock = &mut *lookup.lock; + + let result = get_cache(lock).raw_entry().from_key_hashed_nocheck(lookup.key_hash, &key); + + if let Some((_, value)) = result { on_hit(&value.0, value.1) } else { on_miss(key, lookup) } + } + + #[inline] + fn complete( + &self, + _: TyCtxt<'tcx>, + lock_sharded_storage: &mut Self::Sharded, + key: K, + value: V, + index: DepNodeIndex, + ) { + lock_sharded_storage.insert(key, (value, index)); + } + + fn iter( + &self, + shards: &Sharded, + get_shard: impl Fn(&mut L) -> &mut Self::Sharded, + f: impl for<'a> FnOnce(Box + 'a>) -> R, + ) -> R { + let mut shards = shards.lock_shards(); + let mut shards: Vec<_> = shards.iter_mut().map(|shard| get_shard(shard)).collect(); + let results = shards.iter_mut().flat_map(|shard| shard.iter()).map(|(k, v)| (k, &v.0, v.1)); + f(Box::new(results)) + } +} diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index dbb6a1080e6..178c2362def 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -1,15 +1,14 @@ use crate::dep_graph::SerializedDepNodeIndex; use crate::dep_graph::{DepKind, DepNode}; +use crate::ty::query::caches::QueryCache; use crate::ty::query::plumbing::CycleError; -use crate::ty::query::queries; -use crate::ty::query::{Query, QueryCache}; +use crate::ty::query::{Query, QueryState}; use crate::ty::TyCtxt; use rustc_data_structures::profiling::ProfileCategory; -use rustc_hir::def_id::{CrateNum, DefId}; +use rustc_hir::def_id::DefId; use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::sharded::Sharded; use std::borrow::Cow; use std::fmt::Debug; use std::hash::Hash; @@ -30,10 +29,12 @@ pub(crate) trait QueryAccessors<'tcx>: QueryConfig<'tcx> { const ANON: bool; const EVAL_ALWAYS: bool; + type Cache: QueryCache; + fn query(key: Self::Key) -> Query<'tcx>; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_cache<'a>(tcx: TyCtxt<'tcx>) -> &'a Sharded>; + fn query_state<'a>(tcx: TyCtxt<'tcx>) -> &'a QueryState<'tcx, Self>; fn to_dep_node(tcx: TyCtxt<'tcx>, key: &Self::Key) -> DepNode; @@ -61,7 +62,10 @@ pub(crate) trait QueryDescription<'tcx>: QueryAccessors<'tcx> { } } -impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M { +impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M +where + >::Cache: QueryCache>::Value>, +{ default fn describe(tcx: TyCtxt<'_>, def_id: DefId) -> Cow<'static, str> { if !tcx.sess.verbose() { format!("processing `{}`", tcx.def_path_str(def_id)).into() @@ -82,9 +86,3 @@ impl<'tcx, M: QueryAccessors<'tcx, Key = DefId>> QueryDescription<'tcx> for M { bug!("QueryDescription::load_from_disk() called for an unsupported query.") } } - -impl<'tcx> QueryDescription<'tcx> for queries::analysis<'tcx> { - fn describe(_tcx: TyCtxt<'_>, _: CrateNum) -> Cow<'static, str> { - "running analysis passes on this crate".into() - } -} diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index 393125f278c..4e88fc54637 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -1,13 +1,15 @@ +use crate::dep_graph::DepKind; use crate::ty::context::TyCtxt; use crate::ty::query::plumbing::CycleError; use crate::ty::query::Query; use crate::ty::tls; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::fx::FxHashMap; use rustc_span::Span; -#[cfg(not(parallel_compiler))] -use std::ptr; +use std::convert::TryFrom; +use std::marker::PhantomData; +use std::num::NonZeroU32; #[cfg(parallel_compiler)] use { @@ -15,6 +17,7 @@ use { rustc_data_structures::fx::FxHashSet, rustc_data_structures::stable_hasher::{HashStable, StableHasher}, rustc_data_structures::sync::Lock, + rustc_data_structures::sync::Lrc, rustc_data_structures::{jobserver, OnDrop}, rustc_rayon_core as rayon_core, rustc_span::DUMMY_SP, @@ -30,61 +33,130 @@ pub struct QueryInfo<'tcx> { pub query: Query<'tcx>, } -/// Representss an object representing an active query job. -pub struct QueryJob<'tcx> { +type QueryMap<'tcx> = FxHashMap>; + +/// A value uniquely identifiying an active query job within a shard in the query cache. +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct QueryShardJobId(pub NonZeroU32); + +/// A value uniquely identifiying an active query job. +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct QueryJobId { + /// Which job within a shard is this + pub job: QueryShardJobId, + + /// In which shard is this job + pub shard: u16, + + /// What kind of query this job is + pub kind: DepKind, +} + +impl QueryJobId { + pub fn new(job: QueryShardJobId, shard: usize, kind: DepKind) -> Self { + QueryJobId { job, shard: u16::try_from(shard).unwrap(), kind } + } + + fn query<'tcx>(self, map: &QueryMap<'tcx>) -> Query<'tcx> { + map.get(&self).unwrap().info.query.clone() + } + + #[cfg(parallel_compiler)] + fn span(self, map: &QueryMap<'_>) -> Span { + map.get(&self).unwrap().job.span + } + + #[cfg(parallel_compiler)] + fn parent(self, map: &QueryMap<'_>) -> Option { + map.get(&self).unwrap().job.parent + } + + #[cfg(parallel_compiler)] + fn latch<'a, 'tcx>(self, map: &'a QueryMap<'tcx>) -> Option<&'a QueryLatch<'tcx>> { + map.get(&self).unwrap().job.latch.as_ref() + } +} + +pub struct QueryJobInfo<'tcx> { pub info: QueryInfo<'tcx>, + pub job: QueryJob<'tcx>, +} + +/// Represents an active query job. +#[derive(Clone)] +pub struct QueryJob<'tcx> { + pub id: QueryShardJobId, + + /// The span corresponding to the reason for which this query was required. + pub span: Span, /// The parent query job which created this job and is implicitly waiting on it. - pub parent: Option>>, + pub parent: Option, /// The latch that is used to wait on this job. #[cfg(parallel_compiler)] - latch: QueryLatch<'tcx>, + latch: Option>, + + dummy: PhantomData>, } impl<'tcx> QueryJob<'tcx> { /// Creates a new query job. - pub fn new(info: QueryInfo<'tcx>, parent: Option>>) -> Self { + pub fn new(id: QueryShardJobId, span: Span, parent: Option) -> Self { QueryJob { - info, + id, + span, parent, #[cfg(parallel_compiler)] - latch: QueryLatch::new(), + latch: None, + dummy: PhantomData, } } - /// Awaits for the query job to complete. #[cfg(parallel_compiler)] - pub(super) fn r#await(&self, tcx: TyCtxt<'tcx>, span: Span) -> Result<(), CycleError<'tcx>> { - tls::with_related_context(tcx, move |icx| { - let waiter = Lrc::new(QueryWaiter { - query: icx.query.clone(), - span, - cycle: Lock::new(None), - condvar: Condvar::new(), - }); - self.latch.r#await(&waiter); - // FIXME: Get rid of this lock. We have ownership of the QueryWaiter - // although another thread may still have a Lrc reference so we cannot - // use Lrc::get_mut - let mut cycle = waiter.cycle.lock(); - match cycle.take() { - None => Ok(()), - Some(cycle) => Err(cycle), - } - }) + pub(super) fn latch(&mut self, _id: QueryJobId) -> QueryLatch<'tcx> { + if self.latch.is_none() { + self.latch = Some(QueryLatch::new()); + } + self.latch.as_ref().unwrap().clone() } #[cfg(not(parallel_compiler))] + pub(super) fn latch(&mut self, id: QueryJobId) -> QueryLatch<'tcx> { + QueryLatch { id, dummy: PhantomData } + } + + /// Signals to waiters that the query is complete. + /// + /// This does nothing for single threaded rustc, + /// as there are no concurrent jobs which could be waiting on us + pub fn signal_complete(self) { + #[cfg(parallel_compiler)] + self.latch.map(|latch| latch.set()); + } +} + +#[cfg(not(parallel_compiler))] +#[derive(Clone)] +pub(super) struct QueryLatch<'tcx> { + id: QueryJobId, + dummy: PhantomData<&'tcx ()>, +} + +#[cfg(not(parallel_compiler))] +impl<'tcx> QueryLatch<'tcx> { pub(super) fn find_cycle_in_stack(&self, tcx: TyCtxt<'tcx>, span: Span) -> CycleError<'tcx> { + let query_map = tcx.queries.try_collect_active_jobs().unwrap(); + // Get the current executing query (waiter) and find the waitee amongst its parents - let mut current_job = tls::with_related_context(tcx, |icx| icx.query.clone()); + let mut current_job = tls::with_related_context(tcx, |icx| icx.query); let mut cycle = Vec::new(); while let Some(job) = current_job { - cycle.push(job.info.clone()); + let info = query_map.get(&job).unwrap(); + cycle.push(info.info.clone()); - if ptr::eq(&*job, self) { + if job == self.id { cycle.reverse(); // This is the end of the cycle @@ -93,35 +165,24 @@ impl<'tcx> QueryJob<'tcx> { // Replace it with the span which caused the cycle to form cycle[0].span = span; // Find out why the cycle itself was used - let usage = - job.parent.as_ref().map(|parent| (job.info.span, parent.info.query.clone())); + let usage = info + .job + .parent + .as_ref() + .map(|parent| (info.info.span, parent.query(&query_map))); return CycleError { usage, cycle }; } - current_job = job.parent.clone(); + current_job = info.job.parent; } panic!("did not find a cycle") } - - /// Signals to waiters that the query is complete. - /// - /// This does nothing for single threaded rustc, - /// as there are no concurrent jobs which could be waiting on us - pub fn signal_complete(&self) { - #[cfg(parallel_compiler)] - self.latch.set(); - } - - #[cfg(parallel_compiler)] - fn as_ptr(&self) -> *const QueryJob<'tcx> { - self as *const _ - } } #[cfg(parallel_compiler)] struct QueryWaiter<'tcx> { - query: Option>>, + query: Option, condvar: Condvar, span: Span, cycle: Lock>>, @@ -142,18 +203,43 @@ struct QueryLatchInfo<'tcx> { } #[cfg(parallel_compiler)] -struct QueryLatch<'tcx> { - info: Mutex>, +#[derive(Clone)] +pub(super) struct QueryLatch<'tcx> { + info: Lrc>>, } #[cfg(parallel_compiler)] impl<'tcx> QueryLatch<'tcx> { fn new() -> Self { - QueryLatch { info: Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() }) } + QueryLatch { + info: Lrc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })), + } + } + + /// Awaits for the query job to complete. + #[cfg(parallel_compiler)] + pub(super) fn wait_on(&self, tcx: TyCtxt<'tcx>, span: Span) -> Result<(), CycleError<'tcx>> { + tls::with_related_context(tcx, move |icx| { + let waiter = Lrc::new(QueryWaiter { + query: icx.query, + span, + cycle: Lock::new(None), + condvar: Condvar::new(), + }); + self.wait_on_inner(&waiter); + // FIXME: Get rid of this lock. We have ownership of the QueryWaiter + // although another thread may still have a Lrc reference so we cannot + // use Lrc::get_mut + let mut cycle = waiter.cycle.lock(); + match cycle.take() { + None => Ok(()), + Some(cycle) => Err(cycle), + } + }) } /// Awaits the caller on this latch by blocking the current thread. - fn r#await(&self, waiter: &Lrc>) { + fn wait_on_inner(&self, waiter: &Lrc>) { let mut info = self.info.lock(); if !info.complete { // We push the waiter on to the `waiters` list. It can be accessed inside @@ -197,7 +283,7 @@ impl<'tcx> QueryLatch<'tcx> { /// A resumable waiter of a query. The usize is the index into waiters in the query's latch #[cfg(parallel_compiler)] -type Waiter<'tcx> = (Lrc>, usize); +type Waiter = (QueryJobId, usize); /// Visits all the non-resumable and resumable waiters of a query. /// Only waiters in a query are visited. @@ -209,26 +295,33 @@ type Waiter<'tcx> = (Lrc>, usize); /// required information to resume the waiter. /// If all `visit` calls returns None, this function also returns None. #[cfg(parallel_compiler)] -fn visit_waiters<'tcx, F>(query: Lrc>, mut visit: F) -> Option>> +fn visit_waiters<'tcx, F>( + query_map: &QueryMap<'tcx>, + query: QueryJobId, + mut visit: F, +) -> Option> where - F: FnMut(Span, Lrc>) -> Option>>, + F: FnMut(Span, QueryJobId) -> Option>, { // Visit the parent query which is a non-resumable waiter since it's on the same stack - if let Some(ref parent) = query.parent { - if let Some(cycle) = visit(query.info.span, parent.clone()) { + if let Some(parent) = query.parent(query_map) { + if let Some(cycle) = visit(query.span(query_map), parent) { return Some(cycle); } } // Visit the explicit waiters which use condvars and are resumable - for (i, waiter) in query.latch.info.lock().waiters.iter().enumerate() { - if let Some(ref waiter_query) = waiter.query { - if visit(waiter.span, waiter_query.clone()).is_some() { - // Return a value which indicates that this waiter can be resumed - return Some(Some((query.clone(), i))); + if let Some(latch) = query.latch(query_map) { + for (i, waiter) in latch.info.lock().waiters.iter().enumerate() { + if let Some(waiter_query) = waiter.query { + if visit(waiter.span, waiter_query).is_some() { + // Return a value which indicates that this waiter can be resumed + return Some(Some((query, i))); + } } } } + None } @@ -238,13 +331,14 @@ where /// the cycle. #[cfg(parallel_compiler)] fn cycle_check<'tcx>( - query: Lrc>, + query_map: &QueryMap<'tcx>, + query: QueryJobId, span: Span, - stack: &mut Vec<(Span, Lrc>)>, - visited: &mut FxHashSet<*const QueryJob<'tcx>>, -) -> Option>> { - if !visited.insert(query.as_ptr()) { - return if let Some(p) = stack.iter().position(|q| q.1.as_ptr() == query.as_ptr()) { + stack: &mut Vec<(Span, QueryJobId)>, + visited: &mut FxHashSet, +) -> Option> { + if !visited.insert(query) { + return if let Some(p) = stack.iter().position(|q| q.1 == query) { // We detected a query cycle, fix up the initial span and return Some // Remove previous stack entries @@ -258,10 +352,12 @@ fn cycle_check<'tcx>( } // Query marked as visited is added it to the stack - stack.push((span, query.clone())); + stack.push((span, query)); // Visit all the waiters - let r = visit_waiters(query, |span, successor| cycle_check(successor, span, stack, visited)); + let r = visit_waiters(query_map, query, |span, successor| { + cycle_check(query_map, successor, span, stack, visited) + }); // Remove the entry in our stack if we didn't find a cycle if r.is_none() { @@ -276,26 +372,30 @@ fn cycle_check<'tcx>( /// This is achieved with a depth first search. #[cfg(parallel_compiler)] fn connected_to_root<'tcx>( - query: Lrc>, - visited: &mut FxHashSet<*const QueryJob<'tcx>>, + query_map: &QueryMap<'tcx>, + query: QueryJobId, + visited: &mut FxHashSet, ) -> bool { // We already visited this or we're deliberately ignoring it - if !visited.insert(query.as_ptr()) { + if !visited.insert(query) { return false; } // This query is connected to the root (it has no query parent), return true - if query.parent.is_none() { + if query.parent(query_map).is_none() { return true; } - visit_waiters(query, |_, successor| connected_to_root(successor, visited).then_some(None)) - .is_some() + visit_waiters(query_map, query, |_, successor| { + connected_to_root(query_map, successor, visited).then_some(None) + }) + .is_some() } // Deterministically pick an query from a list #[cfg(parallel_compiler)] -fn pick_query<'a, 'tcx, T, F: Fn(&T) -> (Span, Lrc>)>( +fn pick_query<'a, 'tcx, T, F: Fn(&T) -> (Span, QueryJobId)>( + query_map: &QueryMap<'tcx>, tcx: TyCtxt<'tcx>, queries: &'a [T], f: F, @@ -308,7 +408,7 @@ fn pick_query<'a, 'tcx, T, F: Fn(&T) -> (Span, Lrc>)>( .min_by_key(|v| { let (span, query) = f(v); let mut stable_hasher = StableHasher::new(); - query.info.query.hash_stable(&mut hcx, &mut stable_hasher); + query.query(query_map).hash_stable(&mut hcx, &mut stable_hasher); // Prefer entry points which have valid spans for nicer error messages // We add an integer to the tuple ensuring that entry points // with valid spans are picked first @@ -325,14 +425,17 @@ fn pick_query<'a, 'tcx, T, F: Fn(&T) -> (Span, Lrc>)>( /// the function returns false. #[cfg(parallel_compiler)] fn remove_cycle<'tcx>( - jobs: &mut Vec>>, + query_map: &QueryMap<'tcx>, + jobs: &mut Vec, wakelist: &mut Vec>>, tcx: TyCtxt<'tcx>, ) -> bool { let mut visited = FxHashSet::default(); let mut stack = Vec::new(); // Look for a cycle starting with the last query in `jobs` - if let Some(waiter) = cycle_check(jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited) { + if let Some(waiter) = + cycle_check(query_map, jobs.pop().unwrap(), DUMMY_SP, &mut stack, &mut visited) + { // The stack is a vector of pairs of spans and queries; reverse it so that // the earlier entries require later entries let (mut spans, queries): (Vec<_>, Vec<_>) = stack.into_iter().rev().unzip(); @@ -345,27 +448,25 @@ fn remove_cycle<'tcx>( // Remove the queries in our cycle from the list of jobs to look at for r in &stack { - if let Some(pos) = jobs.iter().position(|j| j.as_ptr() == r.1.as_ptr()) { - jobs.remove(pos); - } + jobs.remove_item(&r.1); } // Find the queries in the cycle which are // connected to queries outside the cycle let entry_points = stack .iter() - .filter_map(|(span, query)| { - if query.parent.is_none() { + .filter_map(|&(span, query)| { + if query.parent(query_map).is_none() { // This query is connected to the root (it has no query parent) - Some((*span, query.clone(), None)) + Some((span, query, None)) } else { let mut waiters = Vec::new(); // Find all the direct waiters who lead to the root - visit_waiters(query.clone(), |span, waiter| { + visit_waiters(query_map, query, |span, waiter| { // Mark all the other queries in the cycle as already visited - let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1.as_ptr())); + let mut visited = FxHashSet::from_iter(stack.iter().map(|q| q.1)); - if connected_to_root(waiter.clone(), &mut visited) { + if connected_to_root(query_map, waiter, &mut visited) { waiters.push((span, waiter)); } @@ -375,31 +476,30 @@ fn remove_cycle<'tcx>( None } else { // Deterministically pick one of the waiters to show to the user - let waiter = pick_query(tcx, &waiters, |s| s.clone()).clone(); - Some((*span, query.clone(), Some(waiter))) + let waiter = *pick_query(query_map, tcx, &waiters, |s| *s); + Some((span, query, Some(waiter))) } } }) - .collect::>, Option<(Span, Lrc>)>)>>(); + .collect::)>>(); // Deterministically pick an entry point - let (_, entry_point, usage) = pick_query(tcx, &entry_points, |e| (e.0, e.1.clone())); + let (_, entry_point, usage) = pick_query(query_map, tcx, &entry_points, |e| (e.0, e.1)); // Shift the stack so that our entry point is first - let entry_point_pos = - stack.iter().position(|(_, query)| query.as_ptr() == entry_point.as_ptr()); + let entry_point_pos = stack.iter().position(|(_, query)| query == entry_point); if let Some(pos) = entry_point_pos { stack.rotate_left(pos); } - let usage = usage.as_ref().map(|(span, query)| (*span, query.info.query.clone())); + let usage = usage.as_ref().map(|(span, query)| (*span, query.query(query_map))); // Create the cycle error let error = CycleError { usage, cycle: stack .iter() - .map(|&(s, ref q)| QueryInfo { span: s, query: q.info.query.clone() }) + .map(|&(s, ref q)| QueryInfo { span: s, query: q.query(query_map) }) .collect(), }; @@ -408,7 +508,7 @@ fn remove_cycle<'tcx>( let (waitee_query, waiter_idx) = waiter.unwrap(); // Extract the waiter we want to resume - let waiter = waitee_query.latch.extract_waiter(waiter_idx); + let waiter = waitee_query.latch(query_map).unwrap().extract_waiter(waiter_idx); // Set the cycle error so it will be picked up when resumed *waiter.cycle.lock() = Some(error); @@ -435,11 +535,11 @@ pub unsafe fn handle_deadlock() { let rustc_span_globals = rustc_span::GLOBALS.with(|rustc_span_globals| rustc_span_globals as *const _); let rustc_span_globals = &*rustc_span_globals; - let syntax_globals = syntax::attr::GLOBALS.with(|syntax_globals| syntax_globals as *const _); + let syntax_globals = rustc_ast::attr::GLOBALS.with(|syntax_globals| syntax_globals as *const _); let syntax_globals = &*syntax_globals; thread::spawn(move || { tls::GCX_PTR.set(gcx_ptr, || { - syntax::attr::GLOBALS.set(syntax_globals, || { + rustc_ast::attr::GLOBALS.set(syntax_globals, || { rustc_span::GLOBALS .set(rustc_span_globals, || tls::with_global(|tcx| deadlock(tcx, ®istry))) }); @@ -460,12 +560,13 @@ fn deadlock(tcx: TyCtxt<'_>, registry: &rayon_core::Registry) { }); let mut wakelist = Vec::new(); - let mut jobs: Vec<_> = tcx.queries.collect_active_jobs(); + let query_map = tcx.queries.try_collect_active_jobs().unwrap(); + let mut jobs: Vec = query_map.keys().cloned().collect(); let mut found_cycle = false; while jobs.len() > 0 { - if remove_cycle(&mut jobs, &mut wakelist, tcx) { + if remove_cycle(&query_map, &mut jobs, &mut wakelist, tcx) { found_cycle = true; } } diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index c1c88e96f94..6073d3a545f 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -4,15 +4,18 @@ use crate::infer::canonical::Canonical; use crate::mir; use crate::traits; use crate::ty::fast_reject::SimplifiedType; +use crate::ty::query::caches::DefaultCacheSelector; use crate::ty::subst::SubstsRef; use crate::ty::{self, Ty, TyCtxt}; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; /// The `Key` trait controls what types can legally be used as the key /// for a query. -pub(super) trait Key { +pub trait Key { + type CacheSelector; + /// Given an instance of this key, what crate is it referring to? /// This is used to find the provider. fn query_crate(&self) -> CrateNum; @@ -23,6 +26,8 @@ pub(super) trait Key { } impl<'tcx> Key for ty::InstanceDef<'tcx> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -33,6 +38,8 @@ impl<'tcx> Key for ty::InstanceDef<'tcx> { } impl<'tcx> Key for ty::Instance<'tcx> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -43,6 +50,8 @@ impl<'tcx> Key for ty::Instance<'tcx> { } impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { self.instance.query_crate() } @@ -53,6 +62,8 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { } impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -63,6 +74,8 @@ impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> { } impl Key for CrateNum { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { *self } @@ -71,16 +84,20 @@ impl Key for CrateNum { } } -impl Key for DefIndex { +impl Key for LocalDefId { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { - LOCAL_CRATE + self.to_def_id().query_crate() } - fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { - DUMMY_SP + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + self.to_def_id().default_span(tcx) } } impl Key for DefId { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { self.krate } @@ -90,6 +107,8 @@ impl Key for DefId { } impl Key for (DefId, DefId) { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { self.0.krate } @@ -99,6 +118,8 @@ impl Key for (DefId, DefId) { } impl Key for (CrateNum, DefId) { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { self.0 } @@ -108,6 +129,8 @@ impl Key for (CrateNum, DefId) { } impl Key for (DefId, SimplifiedType) { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { self.0.krate } @@ -117,6 +140,8 @@ impl Key for (DefId, SimplifiedType) { } impl<'tcx> Key for SubstsRef<'tcx> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -126,6 +151,8 @@ impl<'tcx> Key for SubstsRef<'tcx> { } impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { self.0.krate } @@ -135,6 +162,8 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { } impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { self.1.def_id().krate } @@ -144,6 +173,8 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { } impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -153,6 +184,8 @@ impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) { } impl<'tcx> Key for ty::PolyTraitRef<'tcx> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { self.def_id().krate } @@ -162,6 +195,8 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> { } impl<'tcx> Key for &'tcx ty::Const<'tcx> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -171,6 +206,8 @@ impl<'tcx> Key for &'tcx ty::Const<'tcx> { } impl<'tcx> Key for Ty<'tcx> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -180,6 +217,8 @@ impl<'tcx> Key for Ty<'tcx> { } impl<'tcx> Key for ty::ParamEnv<'tcx> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -189,6 +228,8 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> { } impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { self.value.query_crate() } @@ -198,6 +239,8 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { } impl<'tcx> Key for traits::Environment<'tcx> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -207,6 +250,8 @@ impl<'tcx> Key for traits::Environment<'tcx> { } impl Key for Symbol { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -218,6 +263,8 @@ impl Key for Symbol { /// Canonical query goals correspond to abstract trait operations that /// are not tied to any crate in particular. impl<'tcx, T> Key for Canonical<'tcx, T> { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -228,6 +275,8 @@ impl<'tcx, T> Key for Canonical<'tcx, T> { } impl Key for (Symbol, u32, u32) { + type CacheSelector = DefaultCacheSelector; + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 2c51a093427..7ac8358c78a 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -1,5 +1,7 @@ -use crate::dep_graph::{self, DepNode}; +use crate::dep_graph::{self, DepConstructor, DepNode, DepNodeParams}; use crate::hir::exports::Export; +use crate::hir::map; +use crate::hir::{HirOwner, HirOwnerItems}; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintLevelMap; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -14,20 +16,18 @@ use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLife use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; -use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult}; +use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult, ConstValue}; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; -use crate::session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; -use crate::session::CrateDisambiguator; -use crate::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint}; -use crate::traits::query::method_autoderef::MethodAutoderefStepsResult; -use crate::traits::query::normalize::NormalizationResult; -use crate::traits::query::outlives_bounds::OutlivesBound; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution, }; +use crate::traits::query::{ + DropckOutlivesResult, DtorckConstraint, MethodAutoderefStepsResult, NormalizationResult, + OutlivesBound, +}; use crate::traits::specialization_graph; use crate::traits::Clauses; use crate::traits::{self, Vtable}; @@ -44,29 +44,36 @@ use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId}; use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate}; use rustc_index::vec::IndexVec; +use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; +use rustc_session::CrateDisambiguator; use rustc_target::spec::PanicStrategy; +use rustc_ast::ast; use rustc_attr as attr; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; -use std::any::type_name; use std::borrow::Cow; +use std::collections::BTreeMap; +use std::convert::TryFrom; use std::ops::Deref; use std::sync::Arc; -use syntax::ast; #[macro_use] mod plumbing; +pub use self::plumbing::CycleError; use self::plumbing::*; -pub use self::plumbing::{force_from_dep_node, CycleError}; + +mod stats; +pub use self::stats::print_stats; mod job; #[cfg(parallel_compiler)] pub use self::job::handle_deadlock; -pub use self::job::{QueryInfo, QueryJob}; +use self::job::QueryJobInfo; +pub use self::job::{QueryInfo, QueryJob, QueryJobId}; mod keys; use self::keys::Key; @@ -74,6 +81,9 @@ use self::keys::Key; mod values; use self::values::Value; +mod caches; +use self::caches::CacheSelector; + mod config; use self::config::QueryAccessors; pub use self::config::QueryConfig; @@ -97,9 +107,102 @@ pub use self::profiling_support::{IntoSelfProfilingString, QueryKeyStringBuilder // Queries marked with `fatal_cycle` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. -rustc_query_append! { [define_queries!][ <'tcx> - Other { - /// Runs analysis passes on the crate. - [eval_always] fn analysis: Analysis(CrateNum) -> Result<(), ErrorReported>, - }, -]} +rustc_query_append! { [define_queries!][<'tcx>] } + +/// The red/green evaluation system will try to mark a specific DepNode in the +/// dependency graph as green by recursively trying to mark the dependencies of +/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` +/// where we don't know if it is red or green and we therefore actually have +/// to recompute its value in order to find out. Since the only piece of +/// information that we have at that point is the `DepNode` we are trying to +/// re-evaluate, we need some way to re-run a query from just that. This is what +/// `force_from_dep_node()` implements. +/// +/// In the general case, a `DepNode` consists of a `DepKind` and an opaque +/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint +/// is usually constructed by computing a stable hash of the query-key that the +/// `DepNode` corresponds to. Consequently, it is not in general possible to go +/// back from hash to query-key (since hash functions are not reversible). For +/// this reason `force_from_dep_node()` is expected to fail from time to time +/// because we just cannot find out, from the `DepNode` alone, what the +/// corresponding query-key is and therefore cannot re-run the query. +/// +/// The system deals with this case letting `try_mark_green` fail which forces +/// the root query to be re-evaluated. +/// +/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. +/// Fortunately, we can use some contextual information that will allow us to +/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we +/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a +/// valid `DefPathHash`. Since we also always build a huge table that maps every +/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have +/// everything we need to re-run the query. +/// +/// Take the `mir_validated` query as an example. Like many other queries, it +/// just has a single parameter: the `DefId` of the item it will compute the +/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` +/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` +/// is actually a `DefPathHash`, and can therefore just look up the corresponding +/// `DefId` in `tcx.def_path_hash_to_def_id`. +/// +/// When you implement a new query, it will likely have a corresponding new +/// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As +/// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter, +/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just +/// add it to the "We don't have enough information to reconstruct..." group in +/// the match below. +pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool { + use crate::dep_graph::DepKind; + + // We must avoid ever having to call `force_from_dep_node()` for a + // `DepNode::codegen_unit`: + // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we + // would always end up having to evaluate the first caller of the + // `codegen_unit` query that *is* reconstructible. This might very well be + // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just + // to re-trigger calling the `codegen_unit` query with the right key. At + // that point we would already have re-done all the work we are trying to + // avoid doing in the first place. + // The solution is simple: Just explicitly call the `codegen_unit` query for + // each CGU, right after partitioning. This way `try_mark_green` will always + // hit the cache instead of having to go through `force_from_dep_node`. + // This assertion makes sure, we actually keep applying the solution above. + debug_assert!( + dep_node.kind != DepKind::codegen_unit, + "calling force_from_dep_node() on DepKind::codegen_unit" + ); + + if !dep_node.kind.can_reconstruct_query_key() { + return false; + } + + rustc_dep_node_force!([dep_node, tcx] + // These are inputs that are expected to be pre-allocated and that + // should therefore always be red or green already. + DepKind::CrateMetadata | + + // These are anonymous nodes. + DepKind::TraitSelect | + + // We don't have enough information to reconstruct the query key of + // these. + DepKind::CompileCodegenUnit => { + bug!("force_from_dep_node: encountered {:?}", dep_node) + } + ); + + false +} + +impl DepNode { + /// Check whether the query invocation corresponding to the given + /// DepNode is eligible for on-disk-caching. If so, this is method + /// will execute the query corresponding to the given DepNode. + /// Also, as a sanity check, it expects that the corresponding query + /// invocation has been marked as green already. + pub fn try_load_from_on_disk_cache<'tcx>(&self, tcx: TyCtxt<'tcx>) { + use crate::dep_graph::DepKind; + + rustc_dep_node_try_load_from_on_disk_cache!(self, tcx) + } +} diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 01f684dc65c..781abea75d9 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -3,26 +3,25 @@ use crate::hir::map::definitions::DefPathHash; use crate::ich::{CachingSourceMapView, Fingerprint}; use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use crate::mir::{self, interpret}; -use crate::session::{CrateDisambiguator, Session}; use crate::ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; use crate::ty::context::TyCtxt; use crate::ty::{self, Ty}; +use rustc_ast::ast::Ident; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, Once}; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; -use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; use rustc_index::vec::{Idx, IndexVec}; use rustc_serialize::{ opaque, Decodable, Decoder, Encodable, Encoder, SpecializedDecoder, SpecializedEncoder, UseSpecializedDecodable, UseSpecializedEncodable, }; +use rustc_session::{CrateDisambiguator, Session}; use rustc_span::hygiene::{ExpnId, SyntaxContext}; use rustc_span::source_map::{SourceMap, StableSourceFileId}; use rustc_span::{BytePos, SourceFile, Span, DUMMY_SP}; use std::mem; -use syntax::ast::{Ident, NodeId}; const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; @@ -92,7 +91,7 @@ struct AbsoluteBytePos(u32); impl AbsoluteBytePos { fn new(pos: usize) -> AbsoluteBytePos { - debug_assert!(pos <= ::std::u32::MAX as usize); + debug_assert!(pos <= u32::MAX as usize); AbsoluteBytePos(pos as u32) } @@ -425,7 +424,7 @@ impl<'sess> OnDiskCache<'sess> { //- DECODING ------------------------------------------------------------------- -/// A decoder that can read fro the incr. comp. cache. It is similar to the one +/// A decoder that can read from the incr. comp. cache. It is similar to the one /// we use for crate metadata decoding in that it can rebase spans and eventually /// will also handle things that contain `Ty` instances. struct CacheDecoder<'a, 'tcx> { @@ -657,36 +656,7 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { #[inline] fn specialized_decode(&mut self) -> Result { - Ok(LocalDefId::from_def_id(DefId::decode(self)?)) - } -} - -impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { - fn specialized_decode(&mut self) -> Result { - // Load the `DefPathHash` which is what we encoded the `DefIndex` as. - let def_path_hash = DefPathHash::decode(self)?; - - // Use the `DefPathHash` to map to the current `DefId`. - let def_id = self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash]; - - debug_assert!(def_id.is_local()); - - // The `ItemLocalId` needs no remapping. - let local_id = hir::ItemLocalId::decode(self)?; - - // Reconstruct the `HirId` and look up the corresponding `NodeId` in the - // context of the current session. - Ok(hir::HirId { owner: def_id.index, local_id }) - } -} - -// `NodeId`s are not stable across compilation sessions, so we store them in their -// `HirId` representation. This allows use to map them to the current `NodeId`. -impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { - #[inline] - fn specialized_decode(&mut self) -> Result { - let hir_id = hir::HirId::decode(self)?; - Ok(self.tcx().hir().hir_to_node_id(hir_id)) + Ok(DefId::decode(self)?.expect_local()) } } @@ -883,21 +853,6 @@ where } } -impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - #[inline] - fn specialized_encode(&mut self, id: &hir::HirId) -> Result<(), Self::Error> { - let hir::HirId { owner, local_id } = *id; - - let def_path_hash = self.tcx.hir().definitions().def_path_hash(owner); - - def_path_hash.encode(self)?; - local_id.encode(self) - } -} - impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> where E: 'a + TyEncoder, @@ -928,19 +883,6 @@ where } } -// `NodeId`s are not stable across compilation sessions, so we store them in their -// `HirId` representation. This allows use to map them to the current `NodeId`. -impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> -where - E: 'a + TyEncoder, -{ - #[inline] - fn specialized_encode(&mut self, node_id: &NodeId) -> Result<(), Self::Error> { - let hir_id = self.tcx.hir().node_to_hir_id(*node_id); - hir_id.encode(self) - } -} - impl<'a, 'tcx> SpecializedEncoder for CacheEncoder<'a, 'tcx, opaque::Encoder> { fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> { f.encode_opaque(&mut self.encoder) @@ -966,6 +908,7 @@ where macro_rules! encoder_methods { ($($name:ident($ty:ty);)*) => { + #[inline] $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> { self.encoder.$name(value) })* @@ -1019,7 +962,7 @@ impl SpecializedEncoder for opaque::Encoder { fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> { let start_pos = self.position(); for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE { - ((x.0 >> i * 8) as u8).encode(self)?; + ((x.0 >> (i * 8)) as u8).encode(self)?; } let end_pos = self.position(); assert_eq!((end_pos - start_pos), IntEncodedWithFixedSize::ENCODED_SIZE); @@ -1058,20 +1001,22 @@ where .prof .extra_verbose_generic_activity("encode_query_results_for", ::std::any::type_name::()); - let shards = Q::query_cache(tcx).lock_shards(); - assert!(shards.iter().all(|shard| shard.active.is_empty())); - for (key, entry) in shards.iter().flat_map(|shard| shard.results.iter()) { - if Q::cache_on_disk(tcx, key.clone(), Some(&entry.value)) { - let dep_node = SerializedDepNodeIndex::new(entry.index.index()); + let state = Q::query_state(tcx); + assert!(state.all_inactive()); - // Record position of the cache entry. - query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position()))); + state.iter_results(|results| { + for (key, value, dep_node) in results { + if Q::cache_on_disk(tcx, key.clone(), Some(&value)) { + let dep_node = SerializedDepNodeIndex::new(dep_node.index()); - // Encode the type check tables with the `SerializedDepNodeIndex` - // as tag. - encoder.encode_tagged(dep_node, &entry.value)?; - } - } + // Record position of the cache entry. + query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position()))); - Ok(()) + // Encode the type check tables with the `SerializedDepNodeIndex` + // as tag. + encoder.encode_tagged(dep_node, &value)?; + } + } + Ok(()) + }) } diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 6d9fff351e9..acf67f52dce 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -2,9 +2,10 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; -use crate::ty::query::config::{QueryConfig, QueryDescription}; -use crate::ty::query::job::{QueryInfo, QueryJob}; +use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; +use crate::ty::query::caches::QueryCache; +use crate::ty::query::config::{QueryAccessors, QueryDescription}; +use crate::ty::query::job::{QueryInfo, QueryJob, QueryJobId, QueryShardJobId}; use crate::ty::query::Query; use crate::ty::tls; use crate::ty::{self, TyCtxt}; @@ -12,10 +13,8 @@ use crate::ty::{self, TyCtxt}; #[cfg(not(parallel_compiler))] use rustc_data_structures::cold_path; use rustc_data_structures::fx::{FxHashMap, FxHasher}; -#[cfg(parallel_compiler)] -use rustc_data_structures::profiling::TimingGuard; use rustc_data_structures::sharded::Sharded; -use rustc_data_structures::sync::{Lock, Lrc}; +use rustc_data_structures::sync::{Lock, LockGuard}; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, FatalError, Handler, Level}; use rustc_span::source_map::DUMMY_SP; @@ -23,160 +22,193 @@ use rustc_span::Span; use std::collections::hash_map::Entry; use std::hash::{Hash, Hasher}; use std::mem; +use std::num::NonZeroU32; use std::ptr; +#[cfg(debug_assertions)] +use std::sync::atomic::{AtomicUsize, Ordering}; -pub struct QueryCache<'tcx, D: QueryConfig<'tcx> + ?Sized> { - pub(super) results: FxHashMap>, +pub(crate) struct QueryStateShard<'tcx, D: QueryAccessors<'tcx> + ?Sized> { + pub(super) cache: <>::Cache as QueryCache>::Sharded, pub(super) active: FxHashMap>, - #[cfg(debug_assertions)] - pub(super) cache_hits: usize, + + /// Used to generate unique ids for active jobs. + pub(super) jobs: u32, +} + +impl<'tcx, Q: QueryAccessors<'tcx>> QueryStateShard<'tcx, Q> { + fn get_cache( + &mut self, + ) -> &mut <>::Cache as QueryCache>::Sharded { + &mut self.cache + } } -pub(super) struct QueryValue { - pub(super) value: T, - pub(super) index: DepNodeIndex, +impl<'tcx, Q: QueryAccessors<'tcx>> Default for QueryStateShard<'tcx, Q> { + fn default() -> QueryStateShard<'tcx, Q> { + QueryStateShard { cache: Default::default(), active: Default::default(), jobs: 0 } + } +} + +pub(crate) struct QueryState<'tcx, D: QueryAccessors<'tcx> + ?Sized> { + pub(super) cache: D::Cache, + pub(super) shards: Sharded>, + #[cfg(debug_assertions)] + pub(super) cache_hits: AtomicUsize, } -impl QueryValue { - pub(super) fn new(value: T, dep_node_index: DepNodeIndex) -> QueryValue { - QueryValue { value, index: dep_node_index } +impl<'tcx, Q: QueryAccessors<'tcx>> QueryState<'tcx, Q> { + pub(super) fn get_lookup(&'tcx self, key: &K) -> QueryLookup<'tcx, Q> { + // We compute the key's hash once and then use it for both the + // shard lookup and the hashmap lookup. This relies on the fact + // that both of them use `FxHasher`. + let mut hasher = FxHasher::default(); + key.hash(&mut hasher); + let key_hash = hasher.finish(); + + let shard = self.shards.get_shard_index_by_hash(key_hash); + let lock = self.shards.get_shard_by_index(shard).lock(); + QueryLookup { key_hash, shard, lock } } } /// Indicates the state of a query for a given key in a query map. pub(super) enum QueryResult<'tcx> { /// An already executing query. The query job can be used to await for its completion. - Started(Lrc>), + Started(QueryJob<'tcx>), - /// The query panicked. Queries trying to wait on this will raise a fatal error or + /// The query panicked. Queries trying to wait on this will raise a fatal error which will /// silently panic. Poisoned, } -impl<'tcx, M: QueryConfig<'tcx>> Default for QueryCache<'tcx, M> { - fn default() -> QueryCache<'tcx, M> { - QueryCache { - results: FxHashMap::default(), - active: FxHashMap::default(), +impl<'tcx, M: QueryAccessors<'tcx>> QueryState<'tcx, M> { + pub fn iter_results( + &self, + f: impl for<'a> FnOnce( + Box + 'a>, + ) -> R, + ) -> R { + self.cache.iter(&self.shards, |shard| &mut shard.cache, f) + } + pub fn all_inactive(&self) -> bool { + let shards = self.shards.lock_shards(); + shards.iter().all(|shard| shard.active.is_empty()) + } +} + +impl<'tcx, M: QueryAccessors<'tcx>> Default for QueryState<'tcx, M> { + fn default() -> QueryState<'tcx, M> { + QueryState { + cache: M::Cache::default(), + shards: Default::default(), #[cfg(debug_assertions)] - cache_hits: 0, + cache_hits: AtomicUsize::new(0), } } } +/// Values used when checking a query cache which can be reused on a cache-miss to execute the query. +pub(crate) struct QueryLookup<'tcx, Q: QueryAccessors<'tcx>> { + pub(super) key_hash: u64, + pub(super) shard: usize, + pub(super) lock: LockGuard<'tcx, QueryStateShard<'tcx, Q>>, +} + /// A type representing the responsibility to execute the job in the `job` field. /// This will poison the relevant query if dropped. -pub(super) struct JobOwner<'a, 'tcx, Q: QueryDescription<'tcx>> { - cache: &'a Sharded>, +pub(super) struct JobOwner<'tcx, Q: QueryDescription<'tcx>> { + tcx: TyCtxt<'tcx>, key: Q::Key, - job: Lrc>, + id: QueryJobId, } -impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { +impl<'tcx, Q: QueryDescription<'tcx>> JobOwner<'tcx, Q> { /// Either gets a `JobOwner` corresponding the query, allowing us to /// start executing the query, or returns with the result of the query. - /// If the query is executing elsewhere, this will wait for it. + /// This function assumes that `try_get_cached` is already called and returned `lookup`. + /// If the query is executing elsewhere, this will wait for it and return the result. /// If the query panicked, this will silently panic. /// /// This function is inlined because that results in a noticeable speed-up /// for some compile-time benchmarks. #[inline(always)] - pub(super) fn try_get(tcx: TyCtxt<'tcx>, span: Span, key: &Q::Key) -> TryGetJob<'a, 'tcx, Q> { - // Handling the `query_blocked_prof_timer` is a bit weird because of the - // control flow in this function: Blocking is implemented by - // awaiting a running job and, once that is done, entering the loop below - // again from the top. In that second iteration we will hit the - // cache which provides us with the information we need for - // finishing the "query-blocked" event. - // - // We thus allocate `query_blocked_prof_timer` outside the loop, - // initialize it during the first iteration and finish it during the - // second iteration. - #[cfg(parallel_compiler)] - let mut query_blocked_prof_timer: Option> = None; - - let cache = Q::query_cache(tcx); - loop { - // We compute the key's hash once and then use it for both the - // shard lookup and the hashmap lookup. This relies on the fact - // that both of them use `FxHasher`. - let mut state = FxHasher::default(); - key.hash(&mut state); - let key_hash = state.finish(); - - let mut lock = cache.get_shard_by_hash(key_hash).lock(); - if let Some((_, value)) = - lock.results.raw_entry().from_key_hashed_nocheck(key_hash, key) - { - if unlikely!(tcx.prof.enabled()) { - tcx.prof.query_cache_hit(value.index.into()); + pub(super) fn try_start( + tcx: TyCtxt<'tcx>, + span: Span, + key: &Q::Key, + mut lookup: QueryLookup<'tcx, Q>, + ) -> TryGetJob<'tcx, Q> { + let lock = &mut *lookup.lock; + + let (latch, mut _query_blocked_prof_timer) = match lock.active.entry((*key).clone()) { + Entry::Occupied(mut entry) => { + match entry.get_mut() { + QueryResult::Started(job) => { + // For parallel queries, we'll block and wait until the query running + // in another thread has completed. Record how long we wait in the + // self-profiler. + let _query_blocked_prof_timer = if cfg!(parallel_compiler) { + Some(tcx.prof.query_blocked()) + } else { + None + }; - #[cfg(parallel_compiler)] - { - if let Some(prof_timer) = query_blocked_prof_timer.take() { - prof_timer.finish_with_query_invocation_id(value.index.into()); - } + // Create the id of the job we're waiting for + let id = QueryJobId::new(job.id, lookup.shard, Q::dep_kind()); + + (job.latch(id), _query_blocked_prof_timer) } + QueryResult::Poisoned => FatalError.raise(), } + } + Entry::Vacant(entry) => { + // No job entry for this query. Return a new one to be started later. - let result = (value.value.clone(), value.index); - #[cfg(debug_assertions)] - { - lock.cache_hits += 1; - } - return TryGetJob::JobCompleted(result); + // Generate an id unique within this shard. + let id = lock.jobs.checked_add(1).unwrap(); + lock.jobs = id; + let id = QueryShardJobId(NonZeroU32::new(id).unwrap()); + + let global_id = QueryJobId::new(id, lookup.shard, Q::dep_kind()); + + let job = tls::with_related_context(tcx, |icx| QueryJob::new(id, span, icx.query)); + + entry.insert(QueryResult::Started(job)); + + let owner = JobOwner { tcx, id: global_id, key: (*key).clone() }; + return TryGetJob::NotYetStarted(owner); } + }; + mem::drop(lookup.lock); - let job = match lock.active.entry((*key).clone()) { - Entry::Occupied(entry) => { - match *entry.get() { - QueryResult::Started(ref job) => { - // For parallel queries, we'll block and wait until the query running - // in another thread has completed. Record how long we wait in the - // self-profiler. - #[cfg(parallel_compiler)] - { - query_blocked_prof_timer = Some(tcx.prof.query_blocked()); - } - - job.clone() - } - QueryResult::Poisoned => FatalError.raise(), - } - } - Entry::Vacant(entry) => { - // No job entry for this query. Return a new one to be started later. - return tls::with_related_context(tcx, |icx| { - // Create the `parent` variable before `info`. This allows LLVM - // to elide the move of `info` - let parent = icx.query.clone(); - let info = QueryInfo { span, query: Q::query(key.clone()) }; - let job = Lrc::new(QueryJob::new(info, parent)); - let owner = JobOwner { cache, job: job.clone(), key: (*key).clone() }; - entry.insert(QueryResult::Started(job)); - TryGetJob::NotYetStarted(owner) - }); - } - }; - mem::drop(lock); + // If we are single-threaded we know that we have cycle error, + // so we just return the error. + #[cfg(not(parallel_compiler))] + return TryGetJob::Cycle(cold_path(|| { + Q::handle_cycle_error(tcx, latch.find_cycle_in_stack(tcx, span)) + })); - // If we are single-threaded we know that we have cycle error, - // so we just return the error. - #[cfg(not(parallel_compiler))] - return TryGetJob::Cycle(cold_path(|| { - Q::handle_cycle_error(tcx, job.find_cycle_in_stack(tcx, span)) - })); + // With parallel queries we might just have to wait on some other + // thread. + #[cfg(parallel_compiler)] + { + let result = latch.wait_on(tcx, span); - // With parallel queries we might just have to wait on some other - // thread. - #[cfg(parallel_compiler)] - { - let result = job.r#await(tcx, span); + if let Err(cycle) = result { + return TryGetJob::Cycle(Q::handle_cycle_error(tcx, cycle)); + } - if let Err(cycle) = result { - return TryGetJob::Cycle(Q::handle_cycle_error(tcx, cycle)); - } + let cached = tcx.try_get_cached::( + (*key).clone(), + |value, index| (value.clone(), index), + |_, _| panic!("value must be in cache after waiting"), + ); + + if let Some(prof_timer) = _query_blocked_prof_timer.take() { + prof_timer.finish_with_query_invocation_id(cached.1.into()); } + + return TryGetJob::JobCompleted(cached); } } @@ -186,18 +218,22 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { pub(super) fn complete(self, result: &Q::Value, dep_node_index: DepNodeIndex) { // We can move out of `self` here because we `mem::forget` it below let key = unsafe { ptr::read(&self.key) }; - let job = unsafe { ptr::read(&self.job) }; - let cache = self.cache; + let tcx = self.tcx; // Forget ourself so our destructor won't poison the query mem::forget(self); - let value = QueryValue::new(result.clone(), dep_node_index); - { - let mut lock = cache.get_shard_by_value(&key).lock(); - lock.active.remove(&key); - lock.results.insert(key, value); - } + let job = { + let state = Q::query_state(tcx); + let result = result.clone(); + let mut lock = state.shards.get_shard_by_value(&key).lock(); + let job = match lock.active.remove(&key).unwrap() { + QueryResult::Started(job) => job, + QueryResult::Poisoned => panic!(), + }; + state.cache.complete(tcx, &mut lock.cache, key, result, dep_node_index); + job + }; job.signal_complete(); } @@ -213,16 +249,25 @@ where (result, diagnostics.into_inner()) } -impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> { +impl<'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'tcx, Q> { #[inline(never)] #[cold] fn drop(&mut self) { // Poison the query so jobs waiting on it panic. - let shard = self.cache.get_shard_by_value(&self.key); - shard.lock().active.insert(self.key.clone(), QueryResult::Poisoned); + let state = Q::query_state(self.tcx); + let shard = state.shards.get_shard_by_value(&self.key); + let job = { + let mut shard = shard.lock(); + let job = match shard.active.remove(&self.key).unwrap() { + QueryResult::Started(job) => job, + QueryResult::Poisoned => panic!(), + }; + shard.active.insert(self.key.clone(), QueryResult::Poisoned); + job + }; // Also signal the completion of the job, so waiters // will continue execution. - self.job.signal_complete(); + job.signal_complete(); } } @@ -233,14 +278,15 @@ pub struct CycleError<'tcx> { pub(super) cycle: Vec>, } -/// The result of `try_get_lock`. -pub(super) enum TryGetJob<'a, 'tcx, D: QueryDescription<'tcx>> { +/// The result of `try_start`. +pub(super) enum TryGetJob<'tcx, D: QueryDescription<'tcx>> { /// The query is not yet started. Contains a guard to the cache eventually used to start it. - NotYetStarted(JobOwner<'a, 'tcx, D>), + NotYetStarted(JobOwner<'tcx, D>), /// The query was already completed. /// Returns the result of the query and its dep-node index /// if it succeeded or a cycle error if it failed. + #[cfg(parallel_compiler)] JobCompleted((D::Value, DepNodeIndex)), /// Trying to execute the query resulted in a cycle. @@ -254,7 +300,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline(always)] pub(super) fn start_query( self, - job: Lrc>, + token: QueryJobId, diagnostics: Option<&Lock>>, compute: F, ) -> R @@ -268,7 +314,7 @@ impl<'tcx> TyCtxt<'tcx> { // Update the `ImplicitCtxt` to point to our new query job. let new_icx = tls::ImplicitCtxt { tcx: self, - query: Some(job), + query: Some(token), diagnostics, layout_depth: current_icx.layout_depth, task_deps: current_icx.task_deps, @@ -335,23 +381,31 @@ impl<'tcx> TyCtxt<'tcx> { // state if it was responsible for triggering the panic. tls::with_context_opt(|icx| { if let Some(icx) = icx { - let mut current_query = icx.query.clone(); + let query_map = icx.tcx.queries.try_collect_active_jobs(); + + let mut current_query = icx.query; let mut i = 0; while let Some(query) = current_query { + let query_info = + if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) { + info + } else { + break; + }; let mut diag = Diagnostic::new( Level::FailureNote, &format!( "#{} [{}] {}", i, - query.info.query.name(), - query.info.query.describe(icx.tcx) + query_info.info.query.name(), + query_info.info.query.describe(icx.tcx) ), ); - diag.span = icx.tcx.sess.source_map().def_span(query.info.span).into(); + diag.span = icx.tcx.sess.source_map().def_span(query_info.info.span).into(); handler.force_print_diagnostic(diag); - current_query = query.parent.clone(); + current_query = query_info.job.parent; i += 1; } } @@ -360,13 +414,72 @@ impl<'tcx> TyCtxt<'tcx> { eprintln!("end of query stack"); } + /// Checks if the query is already computed and in the cache. + /// It returns the shard index and a lock guard to the shard, + /// which will be used if the query is not in the cache and we need + /// to compute it. + #[inline(always)] + fn try_get_cached( + self, + key: Q::Key, + // `on_hit` can be called while holding a lock to the query cache + on_hit: OnHit, + on_miss: OnMiss, + ) -> R + where + Q: QueryDescription<'tcx> + 'tcx, + OnHit: FnOnce(&Q::Value, DepNodeIndex) -> R, + OnMiss: FnOnce(Q::Key, QueryLookup<'tcx, Q>) -> R, + { + let state = Q::query_state(self); + + state.cache.lookup( + state, + QueryStateShard::::get_cache, + key, + |value, index| { + if unlikely!(self.prof.enabled()) { + self.prof.query_cache_hit(index.into()); + } + #[cfg(debug_assertions)] + { + state.cache_hits.fetch_add(1, Ordering::Relaxed); + } + on_hit(value, index) + }, + on_miss, + ) + } + #[inline(never)] - pub(super) fn get_query>(self, span: Span, key: Q::Key) -> Q::Value { + pub(super) fn get_query + 'tcx>( + self, + span: Span, + key: Q::Key, + ) -> Q::Value { debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span); - let job = match JobOwner::try_get(self, span, &key) { + self.try_get_cached::( + key, + |value, index| { + self.dep_graph.read_index(index); + value.clone() + }, + |key, lookup| self.try_execute_query::(span, key, lookup), + ) + } + + #[inline(always)] + pub(super) fn try_execute_query>( + self, + span: Span, + key: Q::Key, + lookup: QueryLookup<'tcx, Q>, + ) -> Q::Value { + let job = match JobOwner::try_start(self, span, &key, lookup) { TryGetJob::NotYetStarted(job) => job, TryGetJob::Cycle(result) => return result, + #[cfg(parallel_compiler)] TryGetJob::JobCompleted((v, index)) => { self.dep_graph.read_index(index); return v; @@ -384,7 +497,7 @@ impl<'tcx> TyCtxt<'tcx> { let prof_timer = self.prof.query_provider(); let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { - self.start_query(job.job.clone(), diagnostics, |tcx| { + self.start_query(job.id, diagnostics, |tcx| { tcx.dep_graph.with_anon_task(Q::dep_kind(), || Q::compute(tcx, key)) }) }); @@ -410,7 +523,7 @@ impl<'tcx> TyCtxt<'tcx> { // The diagnostics for this query will be // promoted to the current session during // `try_mark_green()`, so we can ignore them here. - let loaded = self.start_query(job.job.clone(), None, |tcx| { + let loaded = self.start_query(job.id, None, |tcx| { let marked = tcx.dep_graph.try_mark_green_and_read(tcx, &dep_node); marked.map(|(prev_dep_node_index, dep_node_index)| { ( @@ -524,7 +637,7 @@ impl<'tcx> TyCtxt<'tcx> { fn force_query_with_job>( self, key: Q::Key, - job: JobOwner<'_, 'tcx, Q>, + job: JobOwner<'tcx, Q>, dep_node: DepNode, ) -> (Q::Value, DepNodeIndex) { // If the following assertion triggers, it can have two reasons: @@ -544,7 +657,7 @@ impl<'tcx> TyCtxt<'tcx> { let prof_timer = self.prof.query_provider(); let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { - self.start_query(job.job.clone(), diagnostics, |tcx| { + self.start_query(job.id, diagnostics, |tcx| { if Q::EVAL_ALWAYS { tcx.dep_graph.with_eval_always_task( dep_node, @@ -579,7 +692,7 @@ impl<'tcx> TyCtxt<'tcx> { /// side-effects -- e.g., in order to report errors for erroneous programs. /// /// Note: The optimization is only available during incr. comp. - pub(super) fn ensure_query>(self, key: Q::Key) -> () { + pub(super) fn ensure_query + 'tcx>(self, key: Q::Key) -> () { if Q::EVAL_ALWAYS { let _ = self.get_query::(DUMMY_SP, key); return; @@ -607,14 +720,30 @@ impl<'tcx> TyCtxt<'tcx> { } #[allow(dead_code)] - fn force_query>(self, key: Q::Key, span: Span, dep_node: DepNode) { + pub(super) fn force_query + 'tcx>( + self, + key: Q::Key, + span: Span, + dep_node: DepNode, + ) { // We may be concurrently trying both execute and force a query. // Ensure that only one of them runs the query. - let job = match JobOwner::try_get(self, span, &key) { - TryGetJob::NotYetStarted(job) => job, - TryGetJob::Cycle(_) | TryGetJob::JobCompleted(_) => return, - }; - self.force_query_with_job::(key, job, dep_node); + + self.try_get_cached::( + key, + |_, _| { + // Cache hit, do nothing + }, + |key, lookup| { + let job = match JobOwner::try_start(self, span, &key, lookup) { + TryGetJob::NotYetStarted(job) => job, + TryGetJob::Cycle(_) => return, + #[cfg(parallel_compiler)] + TryGetJob::JobCompleted(_) => return, + }; + self.force_query_with_job::(key, job, dep_node); + }, + ); } } @@ -623,17 +752,17 @@ macro_rules! handle_cycle_error { $tcx.report_cycle($error).emit(); Value::from_cycle_error($tcx) }}; - ([fatal_cycle$(, $modifiers:ident)*][$tcx:expr, $error:expr]) => {{ + ([fatal_cycle $($rest:tt)*][$tcx:expr, $error:expr]) => {{ $tcx.report_cycle($error).emit(); $tcx.sess.abort_if_errors(); unreachable!() }}; - ([cycle_delay_bug$(, $modifiers:ident)*][$tcx:expr, $error:expr]) => {{ + ([cycle_delay_bug $($rest:tt)*][$tcx:expr, $error:expr]) => {{ $tcx.report_cycle($error).delay_as_bug(); Value::from_cycle_error($tcx) }}; - ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { - handle_cycle_error!([$($modifiers),*][$($args)*]) + ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { + handle_cycle_error!([$($($modifiers)*)*][$($args)*]) }; } @@ -641,11 +770,11 @@ macro_rules! is_anon { ([]) => {{ false }}; - ([anon$(, $modifiers:ident)*]) => {{ + ([anon $($rest:tt)*]) => {{ true }}; - ([$other:ident$(, $modifiers:ident)*]) => { - is_anon!([$($modifiers),*]) + ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => { + is_anon!([$($($modifiers)*)*]) }; } @@ -653,11 +782,23 @@ macro_rules! is_eval_always { ([]) => {{ false }}; - ([eval_always$(, $modifiers:ident)*]) => {{ + ([eval_always $($rest:tt)*]) => {{ true }}; - ([$other:ident$(, $modifiers:ident)*]) => { - is_eval_always!([$($modifiers),*]) + ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => { + is_eval_always!([$($($modifiers)*)*]) + }; +} + +macro_rules! query_storage { + ([][$K:ty, $V:ty]) => { + <<$K as Key>::CacheSelector as CacheSelector<$K, $V>>::Cache + }; + ([storage($ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => { + $ty + }; + ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { + query_storage!([$($($modifiers)*)*][$($args)*]) }; } @@ -665,11 +806,11 @@ macro_rules! hash_result { ([][$hcx:expr, $result:expr]) => {{ dep_graph::hash_result($hcx, &$result) }}; - ([no_hash$(, $modifiers:ident)*][$hcx:expr, $result:expr]) => {{ + ([no_hash $($rest:tt)*][$hcx:expr, $result:expr]) => {{ None }}; - ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { - hash_result!([$($modifiers),*][$($args)*]) + ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { + hash_result!([$($($modifiers)*)*][$($args)*]) }; } @@ -689,7 +830,6 @@ macro_rules! define_queries_inner { [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { use std::mem; - use rustc_data_structures::sharded::Sharded; use crate::{ rustc_data_structures::stable_hasher::HashStable, rustc_data_structures::stable_hasher::StableHasher, @@ -716,120 +856,38 @@ macro_rules! define_queries_inner { } } - #[cfg(parallel_compiler)] - pub fn collect_active_jobs(&self) -> Vec>> { - let mut jobs = Vec::new(); + pub fn try_collect_active_jobs( + &self + ) -> Option>> { + let mut jobs = FxHashMap::default(); - // We use try_lock_shards here since we are only called from the - // deadlock handler, and this shouldn't be locked. $( - let shards = self.$name.try_lock_shards().unwrap(); - jobs.extend(shards.iter().flat_map(|shard| shard.active.values().filter_map(|v| + // We use try_lock_shards here since we are called from the + // deadlock handler, and this shouldn't be locked. + let shards = self.$name.shards.try_lock_shards()?; + let shards = shards.iter().enumerate(); + jobs.extend(shards.flat_map(|(shard_id, shard)| { + shard.active.iter().filter_map(move |(k, v)| { if let QueryResult::Started(ref job) = *v { - Some(job.clone()) + let id = QueryJobId { + job: job.id, + shard: u16::try_from(shard_id).unwrap(), + kind: + as QueryAccessors<'tcx>>::dep_kind(), + }; + let info = QueryInfo { + span: job.span, + query: queries::$name::query(k.clone()) + }; + Some((id, QueryJobInfo { info, job: job.clone() })) } else { None } - ))); + }) + })); )* - jobs - } - - pub fn print_stats(&self) { - let mut queries = Vec::new(); - - #[derive(Clone)] - struct QueryStats { - name: &'static str, - cache_hits: usize, - key_size: usize, - key_type: &'static str, - value_size: usize, - value_type: &'static str, - entry_count: usize, - } - - fn stats<'tcx, Q: QueryConfig<'tcx>>( - name: &'static str, - map: &Sharded>, - ) -> QueryStats { - let map = map.lock_shards(); - QueryStats { - name, - #[cfg(debug_assertions)] - cache_hits: map.iter().map(|shard| shard.cache_hits).sum(), - #[cfg(not(debug_assertions))] - cache_hits: 0, - key_size: mem::size_of::(), - key_type: type_name::(), - value_size: mem::size_of::(), - value_type: type_name::(), - entry_count: map.iter().map(|shard| shard.results.len()).sum(), - } - } - - $( - queries.push(stats::>( - stringify!($name), - &self.$name, - )); - )* - - if cfg!(debug_assertions) { - let hits: usize = queries.iter().map(|s| s.cache_hits).sum(); - let results: usize = queries.iter().map(|s| s.entry_count).sum(); - println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64); - } - - let mut query_key_sizes = queries.clone(); - query_key_sizes.sort_by_key(|q| q.key_size); - println!("\nLarge query keys:"); - for q in query_key_sizes.iter().rev() - .filter(|q| q.key_size > 8) { - println!( - " {} - {} x {} - {}", - q.name, - q.key_size, - q.entry_count, - q.key_type - ); - } - - let mut query_value_sizes = queries.clone(); - query_value_sizes.sort_by_key(|q| q.value_size); - println!("\nLarge query values:"); - for q in query_value_sizes.iter().rev() - .filter(|q| q.value_size > 8) { - println!( - " {} - {} x {} - {}", - q.name, - q.value_size, - q.entry_count, - q.value_type - ); - } - - if cfg!(debug_assertions) { - let mut query_cache_hits = queries.clone(); - query_cache_hits.sort_by_key(|q| q.cache_hits); - println!("\nQuery cache hits:"); - for q in query_cache_hits.iter().rev() { - println!( - " {} - {} ({}%)", - q.name, - q.cache_hits, - q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64 - ); - } - } - - let mut query_value_count = queries.clone(); - query_value_count.sort_by_key(|q| q.entry_count); - println!("\nQuery value count:"); - for q in query_value_count.iter().rev() { - println!(" {} - {}", q.name, q.entry_count); - } + Some(jobs) } } @@ -906,7 +964,6 @@ macro_rules! define_queries_inner { $(impl<$tcx> QueryConfig<$tcx> for queries::$name<$tcx> { type Key = $K; type Value = $V; - const NAME: &'static str = stringify!($name); const CATEGORY: ProfileCategory = $category; } @@ -915,22 +972,22 @@ macro_rules! define_queries_inner { const ANON: bool = is_anon!([$($modifiers)*]); const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]); + type Cache = query_storage!([$($modifiers)*][$K, $V]); + #[inline(always)] fn query(key: Self::Key) -> Query<'tcx> { Query::$name(key) } #[inline(always)] - fn query_cache<'a>(tcx: TyCtxt<$tcx>) -> &'a Sharded> { + fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<$tcx, Self> { &tcx.queries.$name } #[allow(unused)] #[inline(always)] fn to_dep_node(tcx: TyCtxt<$tcx>, key: &Self::Key) -> DepNode { - use crate::dep_graph::DepConstructor::*; - - DepNode::new(tcx, $node(*key)) + DepConstructor::$node(tcx, *key) } #[inline(always)] @@ -996,7 +1053,7 @@ macro_rules! define_queries_inner { impl TyCtxt<$tcx> { /// Returns a transparent wrapper for `TyCtxt`, which ensures queries - /// are executed instead of just returing their results. + /// are executed instead of just returning their results. #[inline(always)] pub fn ensure(self) -> TyCtxtEnsure<$tcx> { TyCtxtEnsure { @@ -1082,7 +1139,7 @@ macro_rules! define_queries_struct { providers: IndexVec>, fallback_extern_providers: Box>, - $($(#[$attr])* $name: Sharded>>,)* + $($(#[$attr])* $name: QueryState<$tcx, queries::$name<$tcx>>,)* } }; } @@ -1105,105 +1162,3 @@ macro_rules! define_provider_struct { } }; } - -/// The red/green evaluation system will try to mark a specific DepNode in the -/// dependency graph as green by recursively trying to mark the dependencies of -/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode` -/// where we don't know if it is red or green and we therefore actually have -/// to recompute its value in order to find out. Since the only piece of -/// information that we have at that point is the `DepNode` we are trying to -/// re-evaluate, we need some way to re-run a query from just that. This is what -/// `force_from_dep_node()` implements. -/// -/// In the general case, a `DepNode` consists of a `DepKind` and an opaque -/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint -/// is usually constructed by computing a stable hash of the query-key that the -/// `DepNode` corresponds to. Consequently, it is not in general possible to go -/// back from hash to query-key (since hash functions are not reversible). For -/// this reason `force_from_dep_node()` is expected to fail from time to time -/// because we just cannot find out, from the `DepNode` alone, what the -/// corresponding query-key is and therefore cannot re-run the query. -/// -/// The system deals with this case letting `try_mark_green` fail which forces -/// the root query to be re-evaluated. -/// -/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless. -/// Fortunately, we can use some contextual information that will allow us to -/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we -/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a -/// valid `DefPathHash`. Since we also always build a huge table that maps every -/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have -/// everything we need to re-run the query. -/// -/// Take the `mir_validated` query as an example. Like many other queries, it -/// just has a single parameter: the `DefId` of the item it will compute the -/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` -/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` -/// is actually a `DefPathHash`, and can therefore just look up the corresponding -/// `DefId` in `tcx.def_path_hash_to_def_id`. -/// -/// When you implement a new query, it will likely have a corresponding new -/// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As -/// a rule of thumb, if your query takes a `DefId` or `DefIndex` as sole parameter, -/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just -/// add it to the "We don't have enough information to reconstruct..." group in -/// the match below. -pub fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool { - use crate::dep_graph::RecoverKey; - - // We must avoid ever having to call `force_from_dep_node()` for a - // `DepNode::codegen_unit`: - // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we - // would always end up having to evaluate the first caller of the - // `codegen_unit` query that *is* reconstructible. This might very well be - // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just - // to re-trigger calling the `codegen_unit` query with the right key. At - // that point we would already have re-done all the work we are trying to - // avoid doing in the first place. - // The solution is simple: Just explicitly call the `codegen_unit` query for - // each CGU, right after partitioning. This way `try_mark_green` will always - // hit the cache instead of having to go through `force_from_dep_node`. - // This assertion makes sure, we actually keep applying the solution above. - debug_assert!( - dep_node.kind != DepKind::codegen_unit, - "calling force_from_dep_node() on DepKind::codegen_unit" - ); - - if !dep_node.kind.can_reconstruct_query_key() { - return false; - } - - rustc_dep_node_force!([dep_node, tcx] - // These are inputs that are expected to be pre-allocated and that - // should therefore always be red or green already. - DepKind::AllLocalTraitImpls | - DepKind::CrateMetadata | - DepKind::HirBody | - DepKind::Hir | - - // These are anonymous nodes. - DepKind::TraitSelect | - - // We don't have enough information to reconstruct the query key of - // these. - DepKind::CompileCodegenUnit => { - bug!("force_from_dep_node: encountered {:?}", dep_node) - } - - DepKind::Analysis => { - let def_id = if let Some(def_id) = dep_node.extract_def_id(tcx) { - def_id - } else { - // Return from the whole function. - return false - }; - tcx.force_query::>( - def_id.krate, - DUMMY_SP, - *dep_node - ); - } - ); - - true -} diff --git a/src/librustc/ty/query/profiling_support.rs b/src/librustc/ty/query/profiling_support.rs index 79b32ba83ae..99ada34d59e 100644 --- a/src/librustc/ty/query/profiling_support.rs +++ b/src/librustc/ty/query/profiling_support.rs @@ -1,11 +1,10 @@ use crate::hir::map::definitions::DefPathData; use crate::ty::context::TyCtxt; -use crate::ty::query::config::QueryConfig; -use crate::ty::query::plumbing::QueryCache; +use crate::ty::query::config::QueryAccessors; +use crate::ty::query::plumbing::QueryState; use measureme::{StringComponent, StringId}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfiler; -use rustc_data_structures::sharded::Sharded; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use std::fmt::Debug; use std::io::Write; @@ -161,10 +160,10 @@ where pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, Q>( tcx: TyCtxt<'tcx>, query_name: &'static str, - query_cache: &Sharded>, + query_state: &QueryState<'tcx, Q>, string_cache: &mut QueryKeyStringCache, ) where - Q: QueryConfig<'tcx>, + Q: QueryAccessors<'tcx>, { tcx.prof.with_profiler(|profiler| { let event_id_builder = profiler.event_id_builder(); @@ -181,20 +180,8 @@ pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, Q>( // need to invoke queries itself, we cannot keep the query caches // locked while doing so. Instead we copy out the // `(query_key, dep_node_index)` pairs and release the lock again. - let query_keys_and_indices = { - let shards = query_cache.lock_shards(); - let len = shards.iter().map(|shard| shard.results.len()).sum(); - - let mut query_keys_and_indices = Vec::with_capacity(len); - - for shard in &shards { - query_keys_and_indices.extend( - shard.results.iter().map(|(q_key, q_val)| (q_key.clone(), q_val.index)), - ); - } - - query_keys_and_indices - }; + let query_keys_and_indices: Vec<_> = query_state + .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect()); // Now actually allocate the strings. If allocating the strings // generates new entries in the query cache, we'll miss them but @@ -218,18 +205,14 @@ pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, Q>( let query_name = profiler.get_or_alloc_cached_string(query_name); let event_id = event_id_builder.from_label(query_name).to_string_id(); - let shards = query_cache.lock_shards(); + query_state.iter_results(|results| { + let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect(); - for shard in shards.iter() { - let query_invocation_ids = shard - .results - .values() - .map(|v| v.index) - .map(|dep_node_index| dep_node_index.into()); - - profiler - .bulk_map_query_invocation_id_to_single_string(query_invocation_ids, event_id); - } + profiler.bulk_map_query_invocation_id_to_single_string( + query_invocation_ids.into_iter(), + event_id, + ); + }); } }); } diff --git a/src/librustc/ty/query/stats.rs b/src/librustc/ty/query/stats.rs new file mode 100644 index 00000000000..d257320d4ea --- /dev/null +++ b/src/librustc/ty/query/stats.rs @@ -0,0 +1,139 @@ +use crate::ty::query::config::QueryAccessors; +use crate::ty::query::plumbing::QueryState; +use crate::ty::query::queries; +use crate::ty::TyCtxt; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; + +use std::any::type_name; +use std::mem; +#[cfg(debug_assertions)] +use std::sync::atomic::Ordering; + +trait KeyStats { + fn key_stats(&self, stats: &mut QueryStats); +} + +impl KeyStats for T { + default fn key_stats(&self, _: &mut QueryStats) {} +} + +impl KeyStats for DefId { + fn key_stats(&self, stats: &mut QueryStats) { + if self.krate == LOCAL_CRATE { + stats.local_def_id_keys = Some(stats.local_def_id_keys.unwrap_or(0) + 1); + } + } +} + +#[derive(Clone)] +struct QueryStats { + name: &'static str, + cache_hits: usize, + key_size: usize, + key_type: &'static str, + value_size: usize, + value_type: &'static str, + entry_count: usize, + local_def_id_keys: Option, +} + +fn stats<'tcx, Q: QueryAccessors<'tcx>>( + name: &'static str, + map: &QueryState<'tcx, Q>, +) -> QueryStats { + let mut stats = QueryStats { + name, + #[cfg(debug_assertions)] + cache_hits: map.cache_hits.load(Ordering::Relaxed), + #[cfg(not(debug_assertions))] + cache_hits: 0, + key_size: mem::size_of::(), + key_type: type_name::(), + value_size: mem::size_of::(), + value_type: type_name::(), + entry_count: map.iter_results(|results| results.count()), + local_def_id_keys: None, + }; + map.iter_results(|results| { + for (key, _, _) in results { + key.key_stats(&mut stats) + } + }); + stats +} + +pub fn print_stats(tcx: TyCtxt<'_>) { + let queries = query_stats(tcx); + + if cfg!(debug_assertions) { + let hits: usize = queries.iter().map(|s| s.cache_hits).sum(); + let results: usize = queries.iter().map(|s| s.entry_count).sum(); + println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64); + } + + let mut query_key_sizes = queries.clone(); + query_key_sizes.sort_by_key(|q| q.key_size); + println!("\nLarge query keys:"); + for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) { + println!(" {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type); + } + + let mut query_value_sizes = queries.clone(); + query_value_sizes.sort_by_key(|q| q.value_size); + println!("\nLarge query values:"); + for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) { + println!(" {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type); + } + + if cfg!(debug_assertions) { + let mut query_cache_hits = queries.clone(); + query_cache_hits.sort_by_key(|q| q.cache_hits); + println!("\nQuery cache hits:"); + for q in query_cache_hits.iter().rev() { + println!( + " {} - {} ({}%)", + q.name, + q.cache_hits, + q.cache_hits as f64 / (q.cache_hits + q.entry_count) as f64 + ); + } + } + + let mut query_value_count = queries.clone(); + query_value_count.sort_by_key(|q| q.entry_count); + println!("\nQuery value count:"); + for q in query_value_count.iter().rev() { + println!(" {} - {}", q.name, q.entry_count); + } + + let mut def_id_density: Vec<_> = + queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect(); + def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap()); + println!("\nLocal DefId density:"); + let total = tcx.hir().definitions().def_index_count() as f64; + for q in def_id_density.iter().rev() { + let local = q.local_def_id_keys.unwrap(); + println!(" {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total); + } +} + +macro_rules! print_stats { + (<$tcx:tt> $($category:tt { + $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)* + },)*) => { + fn query_stats(tcx: TyCtxt<'_>) -> Vec { + let mut queries = Vec::new(); + + $($( + queries.push(stats::>( + stringify!($name), + &tcx.queries.$name, + )); + )*)* + + queries + } + } +} + +rustc_query_append! { [print_stats!][<'tcx>] } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 3b9df72266f..fb4184a9fb3 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -72,7 +72,7 @@ pub trait TypeRelation<'tcx>: Sized { b: &T, ) -> RelateResult<'tcx, T>; - // Overrideable relations. You shouldn't typically call these + // Overridable relations. You shouldn't typically call these // directly, instead call `relate()`, which in turn calls // these. This is both more uniform but also allows us to add // additional hooks for other types in the future if needed @@ -287,7 +287,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id))) } else { let substs = relate_substs(relation, None, a.substs, b.substs)?; - Ok(ty::TraitRef { def_id: a.def_id, substs: substs }) + Ok(ty::TraitRef { def_id: a.def_id, substs }) } } } @@ -303,7 +303,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id))) } else { let substs = relate_substs(relation, None, a.substs, b.substs)?; - Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs: substs }) + Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs }) } } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 59dd41e9d56..e2fa0313911 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -17,17 +17,6 @@ use std::fmt; use std::rc::Rc; use std::sync::Arc; -impl fmt::Debug for ty::GenericParamDef { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let type_name = match self.kind { - ty::GenericParamDefKind::Lifetime => "Lifetime", - ty::GenericParamDefKind::Type { .. } => "Type", - ty::GenericParamDefKind::Const => "Const", - }; - write!(f, "{}({}, {:?}, {})", type_name, self.name, self.def_id, self.index) - } -} - impl fmt::Debug for ty::TraitDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { @@ -271,8 +260,8 @@ CloneTypeFoldableAndLiftImpls! { u64, String, crate::middle::region::Scope, - ::syntax::ast::FloatTy, - ::syntax::ast::NodeId, + ::rustc_ast::ast::FloatTy, + ::rustc_ast::ast::NodeId, ::rustc_span::symbol::Symbol, ::rustc_hir::def::Res, ::rustc_hir::def_id::DefId, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index a60ea33e8b0..036429e3114 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -17,6 +17,7 @@ use crate::ty::{ }; use crate::ty::{List, ParamEnv, ParamEnvAnd, TyS}; use polonius_engine::Atom; +use rustc_ast::ast::{self, Ident}; use rustc_data_structures::captures::Captures; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -29,7 +30,6 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::marker::PhantomData; use std::ops::Range; -use syntax::ast::{self, Ident}; #[derive( Clone, @@ -118,7 +118,7 @@ impl BoundRegion { } /// N.B., if you change this, you'll probably want to change the corresponding -/// AST structure in `libsyntax/ast.rs` as well. +/// AST structure in `librustc_ast/ast.rs` as well. #[derive( Clone, PartialEq, @@ -1066,11 +1066,7 @@ impl<'tcx> ProjectionTy<'tcx> { ) -> ProjectionTy<'tcx> { let item_def_id = tcx .associated_items(trait_ref.def_id) - .iter() - .find(|item| { - item.kind == ty::AssocKind::Type - && tcx.hygienic_eq(item_name, item.ident, trait_ref.def_id) - }) + .find_by_name_and_kind(tcx, item_name, ty::AssocKind::Type, trait_ref.def_id) .unwrap() .def_id; @@ -1197,7 +1193,7 @@ pub struct ParamTy { impl<'tcx> ParamTy { pub fn new(index: u32, name: Symbol) -> ParamTy { - ParamTy { index, name: name } + ParamTy { index, name } } pub fn for_self() -> ParamTy { @@ -1400,11 +1396,11 @@ pub type Region<'tcx> = &'tcx RegionKind; /// the inference variable is supposed to satisfy the relation /// *for every value of the placeholder region*. To ensure that doesn't /// happen, you can use `leak_check`. This is more clearly explained -/// by the [rustc guide]. +/// by the [rustc dev guide]. /// /// [1]: http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ /// [2]: http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ -/// [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html +/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html #[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable, PartialOrd, Ord)] pub enum RegionKind { /// Region bound in a type or fn declaration which will be @@ -1747,45 +1743,42 @@ impl RegionKind { } } - pub fn keep_in_local_tcx(&self) -> bool { - if let ty::ReVar(..) = self { true } else { false } - } - pub fn type_flags(&self) -> TypeFlags { let mut flags = TypeFlags::empty(); - if self.keep_in_local_tcx() { - flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX; - } - match *self { ty::ReVar(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_INFER; + flags = flags | TypeFlags::KEEP_IN_LOCAL_TCX; } ty::RePlaceholder(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; } - ty::ReLateBound(..) => { - flags = flags | TypeFlags::HAS_RE_LATE_BOUND; - } ty::ReEarlyBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; - flags = flags | TypeFlags::HAS_RE_EARLY_BOUND; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + flags = flags | TypeFlags::HAS_RE_PARAM; } - ty::ReEmpty(_) | ty::ReStatic | ty::ReFree { .. } | ty::ReScope { .. } => { + ty::ReFree { .. } | ty::ReScope { .. } => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; + flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; + } + ty::ReEmpty(_) | ty::ReStatic => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } - ty::ReErased => {} ty::ReClosureBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; } - } - - match *self { - ty::ReStatic | ty::ReEmpty(_) | ty::ReErased | ty::ReLateBound(..) => (), - _ => flags = flags | TypeFlags::HAS_FREE_LOCAL_NAMES, + ty::ReLateBound(..) => { + flags = flags | TypeFlags::HAS_RE_LATE_BOUND; + } + ty::ReErased => { + flags = flags | TypeFlags::HAS_RE_ERASED; + } } debug!("type_flags({:?}) = {:?}", self, flags); @@ -2415,9 +2408,14 @@ pub struct Const<'tcx> { static_assert_size!(Const<'_>, 48); impl<'tcx> Const<'tcx> { + #[inline] + pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self { + tcx.mk_const(Self { val: ConstKind::Value(val), ty }) + } + #[inline] pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> &'tcx Self { - tcx.mk_const(Self { val: ConstKind::Value(ConstValue::Scalar(val)), ty }) + Self::from_value(tcx, ConstValue::Scalar(val), ty) } #[inline] @@ -2481,7 +2479,9 @@ impl<'tcx> Const<'tcx> { // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - tcx.const_eval_resolve(param_env, did, substs, promoted, None).ok() + tcx.const_eval_resolve(param_env, did, substs, promoted, None) + .ok() + .map(|val| Const::from_value(tcx, val, self.ty)) }; match self.val { @@ -2489,8 +2489,8 @@ impl<'tcx> Const<'tcx> { // HACK(eddyb) when substs contain e.g. inference variables, // attempt using identity substs instead, that will succeed // when the expression doesn't depend on any parameters. - // FIXME(eddyb) make `const_eval` a canonical query instead, - // that would properly handle inference variables in `substs`. + // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that + // we can call `infcx.const_eval_resolve` which handles inference variables. if substs.has_local_value() { let identity_substs = InternalSubsts::identity_for_item(tcx, did); // The `ParamEnv` needs to match the `identity_substs`. @@ -2581,7 +2581,7 @@ impl<'tcx> ConstKind<'tcx> { #[inline] pub fn try_to_bits(&self, size: ty::layout::Size) -> Option { - self.try_to_scalar()?.to_bits(size).ok() + if let ConstKind::Value(val) = self { val.try_to_bits(size) } else { None } } } diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 0cf1c397648..b0287be6529 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -5,11 +5,14 @@ use crate::ty::fast_reject; use crate::ty::fold::TypeFoldable; use crate::ty::{Ty, TyCtxt}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{CrateNum, DefId}; +use rustc_hir::HirId; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_errors::ErrorReported; use rustc_macros::HashStable; +use std::collections::BTreeMap; /// A trait's definition with type information. #[derive(HashStable)] @@ -33,11 +36,33 @@ pub struct TraitDef { /// and thus `impl`s of it are allowed to overlap. pub is_marker: bool, + /// Used to determine whether the standard library is allowed to specialize + /// on this trait. + pub specialization_kind: TraitSpecializationKind, + /// The ICH of this trait's DefPath, cached here so it doesn't have to be /// recomputed all the time. pub def_path_hash: DefPathHash, } +/// Whether this trait is treated specially by the standard library +/// specialization lint. +#[derive(HashStable, PartialEq, Clone, Copy, RustcEncodable, RustcDecodable)] +pub enum TraitSpecializationKind { + /// The default. Specializing on this trait is not allowed. + None, + /// Specializing on this trait is allowed because it doesn't have any + /// methods. For example `Sized` or `FusedIterator`. + /// Applies to traits with the `rustc_unsafe_specialization_marker` + /// attribute. + Marker, + /// Specializing on this trait is allowed because all of the impls of this + /// trait are "always applicable". Always applicable means that if + /// `X<'x>: T<'y>` for any lifetimes, then `for<'a, 'b> X<'a>: T<'b>`. + /// Applies to traits with the `rustc_specialization_trait` attribute. + AlwaysApplicable, +} + #[derive(Default)] pub struct TraitImpls { blanket_impls: Vec, @@ -52,16 +77,25 @@ impl<'tcx> TraitDef { paren_sugar: bool, has_auto_impl: bool, is_marker: bool, + specialization_kind: TraitSpecializationKind, def_path_hash: DefPathHash, ) -> TraitDef { - TraitDef { def_id, unsafety, paren_sugar, has_auto_impl, is_marker, def_path_hash } + TraitDef { + def_id, + unsafety, + paren_sugar, + has_auto_impl, + is_marker, + specialization_kind, + def_path_hash, + } } pub fn ancestors( &self, tcx: TyCtxt<'tcx>, of_impl: DefId, - ) -> specialization_graph::Ancestors<'tcx> { + ) -> Result, ErrorReported> { specialization_graph::ancestors(tcx, self.def_id, of_impl) } } @@ -146,6 +180,14 @@ impl<'tcx> TyCtxt<'tcx> { } } +// Query provider for `all_local_trait_impls`. +pub(super) fn all_local_trait_impls<'tcx>( + tcx: TyCtxt<'tcx>, + krate: CrateNum, +) -> &'tcx BTreeMap> { + &tcx.hir_crate(krate).trait_impls +} + // Query provider for `trait_impls_of`. pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> &TraitImpls { let mut impls = TraitImpls::default(); diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index db7b8d8cfd9..69daa2da1fd 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -10,6 +10,7 @@ use crate::ty::TyKind::*; use crate::ty::{self, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable}; use crate::util::common::ErrorReported; use rustc_apfloat::Float as _; +use rustc_ast::ast; use rustc_attr::{self as attr, SignedInt, UnsignedInt}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -21,7 +22,6 @@ use rustc_span::Span; use rustc_target::abi::TargetDataLayout; use smallvec::SmallVec; use std::{cmp, fmt}; -use syntax::ast; #[derive(Copy, Clone, Debug)] pub struct Discr<'tcx> { @@ -50,11 +50,11 @@ fn signed_min(size: Size) -> i128 { } fn signed_max(size: Size) -> i128 { - i128::max_value() >> (128 - size.bits()) + i128::MAX >> (128 - size.bits()) } fn unsigned_max(size: Size) -> u128 { - u128::max_value() >> (128 - size.bits()) + u128::MAX >> (128 - size.bits()) } fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) { @@ -77,7 +77,7 @@ impl<'tcx> Discr<'tcx> { let min = signed_min(size); let max = signed_max(size); let val = sign_extend(self.val, size) as i128; - assert!(n < (i128::max_value() as u128)); + assert!(n < (i128::MAX as u128)); let n = n as i128; let oflo = val > max - n; let val = if oflo { min + (n - (max - val) - 1) } else { val + n }; @@ -346,18 +346,13 @@ impl<'tcx> TyCtxt<'tcx> { adt_did: DefId, validate: &mut dyn FnMut(Self, DefId) -> Result<(), ErrorReported>, ) -> Option { - let drop_trait = if let Some(def_id) = self.lang_items().drop_trait() { - def_id - } else { - return None; - }; - + let drop_trait = self.lang_items().drop_trait()?; self.ensure().coherent_trait(drop_trait); let mut dtor_did = None; let ty = self.type_of(adt_did); self.for_each_relevant_impl(drop_trait, ty, |impl_did| { - if let Some(item) = self.associated_items(impl_did).first() { + if let Some(item) = self.associated_items(impl_did).in_definition_order().next() { if validate(self, impl_did).is_ok() { dtor_did = Some(item.def_id); } @@ -615,7 +610,7 @@ impl<'tcx> TyCtxt<'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { if let ty::Opaque(def_id, substs) = t.kind { self.expand_opaque_ty(def_id, substs).unwrap_or(t) - } else if t.has_projections() { + } else if t.has_opaque_types() { t.super_fold_with(self) } else { t @@ -697,7 +692,7 @@ impl<'tcx> ty::TyS<'tcx> { /// strange rules like `>::Bar: Sized` that /// actually carry lifetime requirements. pub fn is_sized(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - tcx_at.is_sized_raw(param_env.and(self)) + self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self)) } /// Checks whether values of this type `T` implement the `Freeze` @@ -713,7 +708,43 @@ impl<'tcx> ty::TyS<'tcx> { param_env: ty::ParamEnv<'tcx>, span: Span, ) -> bool { - tcx.at(span).is_freeze_raw(param_env.and(self)) + self.is_trivially_freeze() || tcx.at(span).is_freeze_raw(param_env.and(self)) + } + + /// Fast path helper for testing if a type is `Freeze`. + /// + /// Returning true means the type is known to be `Freeze`. Returning + /// `false` means nothing -- could be `Freeze`, might not be. + fn is_trivially_freeze(&self) -> bool { + match self.kind { + ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Bool + | ty::Char + | ty::Str + | ty::Never + | ty::Ref(..) + | ty::RawPtr(_) + | ty::FnDef(..) + | ty::Error + | ty::FnPtr(_) => true, + ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_freeze), + ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(), + ty::Adt(..) + | ty::Bound(..) + | ty::Closure(..) + | ty::Dynamic(..) + | ty::Foreign(_) + | ty::Generator(..) + | ty::GeneratorWitness(_) + | ty::Infer(_) + | ty::Opaque(..) + | ty::Param(_) + | ty::Placeholder(_) + | ty::Projection(_) + | ty::UnnormalizedProjection(_) => false, + } } /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely diff --git a/src/libsyntax/Cargo.toml b/src/librustc_ast/Cargo.toml similarity index 93% rename from src/libsyntax/Cargo.toml rename to src/librustc_ast/Cargo.toml index ff03ae3f425..867bcf79232 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/librustc_ast/Cargo.toml @@ -1,11 +1,11 @@ [package] authors = ["The Rust Project Developers"] -name = "syntax" +name = "rustc_ast" version = "0.0.0" edition = "2018" [lib] -name = "syntax" +name = "rustc_ast" path = "lib.rs" doctest = false diff --git a/src/librustc_ast/README.md b/src/librustc_ast/README.md new file mode 100644 index 00000000000..dd407dba1f4 --- /dev/null +++ b/src/librustc_ast/README.md @@ -0,0 +1,9 @@ +The `rustc_ast` crate contains those things concerned purely with syntax +– that is, the AST ("abstract syntax tree"), parser, pretty-printer, +lexer, macro expander, and utilities for traversing ASTs. + +For more information about how these things work in rustc, see the +rustc dev guide: + +- [Parsing](https://rustc-dev-guide.rust-lang.org/the-parser.html) +- [Macro Expansion](https://rustc-dev-guide.rust-lang.org/macro-expansion.html) diff --git a/src/libsyntax/ast.rs b/src/librustc_ast/ast.rs similarity index 92% rename from src/libsyntax/ast.rs rename to src/librustc_ast/ast.rs index 72430fa9c17..e3077b9897c 100644 --- a/src/libsyntax/ast.rs +++ b/src/librustc_ast/ast.rs @@ -14,7 +14,7 @@ //! - [`Generics`], [`GenericParam`], [`WhereClause`]: Metadata associated with generic parameters. //! - [`EnumDef`] and [`Variant`]: Enum declaration. //! - [`Lit`] and [`LitKind`]: Literal expressions. -//! - [`MacroDef`], [`MacStmtStyle`], [`Mac`], [`MacDelimeter`]: Macro definition and invocation. +//! - [`MacroDef`], [`MacStmtStyle`], [`MacCall`], [`MacDelimeter`]: Macro definition and invocation. //! - [`Attribute`]: Metadata associated with item. //! - [`UnOp`], [`UnOpKind`], [`BinOp`], [`BinOpKind`]: Unary and binary operators. @@ -38,6 +38,7 @@ use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use std::convert::TryFrom; use std::fmt; use std::iter; @@ -243,7 +244,7 @@ pub struct ParenthesizedArgs { pub inputs: Vec>, /// `C` - pub output: FunctionRetTy, + pub output: FnRetTy, } impl ParenthesizedArgs { @@ -429,6 +430,13 @@ pub struct Crate { pub module: Mod, pub attrs: Vec, pub span: Span, + /// The order of items in the HIR is unrelated to the order of + /// items in the AST. However, we generate proc macro harnesses + /// based on the AST order, and later refer to these harnesses + /// from the HIR. This field keeps track of the order in which + /// we generated proc macros harnesses, so that we can map + /// HIR proc macros items back to their harness items. + pub proc_macros: Vec, } /// Possible values inside of compile-time attribute lists. @@ -505,7 +513,7 @@ impl Pat { TyKind::Path(None, Path::from_ident(*ident)) } PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()), - PatKind::Mac(mac) => TyKind::Mac(mac.clone()), + PatKind::MacCall(mac) => TyKind::MacCall(mac.clone()), // `&mut? P` can be reinterpreted as `&mut? T` where `T` is `P` reparsed as a type. PatKind::Ref(pat, mutbl) => { pat.to_ty().map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))? @@ -559,7 +567,7 @@ impl Pat { | PatKind::Range(..) | PatKind::Ident(..) | PatKind::Path(..) - | PatKind::Mac(_) => {} + | PatKind::MacCall(_) => {} } } @@ -674,7 +682,7 @@ pub enum PatKind { Paren(P), /// A macro pattern; pre-expansion. - Mac(Mac), + MacCall(MacCall), } #[derive( @@ -873,9 +881,9 @@ impl Stmt { pub fn add_trailing_semicolon(mut self) -> Self { self.kind = match self.kind { StmtKind::Expr(expr) => StmtKind::Semi(expr), - StmtKind::Mac(mac) => { - StmtKind::Mac(mac.map(|(mac, _style, attrs)| (mac, MacStmtStyle::Semicolon, attrs))) - } + StmtKind::MacCall(mac) => StmtKind::MacCall( + mac.map(|(mac, _style, attrs)| (mac, MacStmtStyle::Semicolon, attrs)), + ), kind => kind, }; self @@ -906,8 +914,10 @@ pub enum StmtKind { Expr(P), /// Expr with a trailing semi-colon. Semi(P), + /// Just a trailing semi-colon. + Empty, /// Macro. - Mac(P<(Mac, MacStmtStyle, AttrVec)>), + MacCall(P<(MacCall, MacStmtStyle, AttrVec)>), } #[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)] @@ -1047,7 +1057,7 @@ impl Expr { let kind = match &self.kind { // Trivial conversions. ExprKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()), - ExprKind::Mac(mac) => TyKind::Mac(mac.clone()), + ExprKind::MacCall(mac) => TyKind::MacCall(mac.clone()), ExprKind::Paren(expr) => expr.to_ty().map(TyKind::Paren)?, @@ -1068,7 +1078,7 @@ impl Expr { // If binary operator is `Add` and both `lhs` and `rhs` are trait bounds, // then type of result is trait object. - // Othewise we don't assume the result type. + // Otherwise we don't assume the result type. ExprKind::Binary(binop, lhs, rhs) if binop.node == BinOpKind::Add => { if let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) { TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None) @@ -1117,7 +1127,7 @@ impl Expr { ExprKind::Continue(..) => ExprPrecedence::Continue, ExprKind::Ret(..) => ExprPrecedence::Ret, ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm, - ExprKind::Mac(..) => ExprPrecedence::Mac, + ExprKind::MacCall(..) => ExprPrecedence::Mac, ExprKind::Struct(..) => ExprPrecedence::Struct, ExprKind::Repeat(..) => ExprPrecedence::Repeat, ExprKind::Paren(..) => ExprPrecedence::Paren, @@ -1249,7 +1259,7 @@ pub enum ExprKind { InlineAsm(P), /// A macro invocation; pre-expansion. - Mac(Mac), + MacCall(MacCall), /// A struct literal expression. /// @@ -1335,13 +1345,13 @@ pub enum Movability { /// Represents a macro invocation. The `path` indicates which macro /// is being invoked, and the `args` are arguments passed to it. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct Mac { +pub struct MacCall { pub path: Path, pub args: P, pub prior_type_ascription: Option<(Span, bool)>, } -impl Mac { +impl MacCall { pub fn span(&self) -> Span { self.path.span.to(self.args.span().unwrap_or(self.path.span)) } @@ -1436,11 +1446,11 @@ impl MacDelimiter { } /// Represents a macro definition. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct MacroDef { pub body: P, /// `true` if macro was defined with `macro_rules`. - pub legacy: bool, + pub macro_rules: bool, } #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, Eq, PartialEq)] @@ -1605,46 +1615,6 @@ pub struct FnSig { pub decl: P, } -/// Represents associated items. -/// These include items in `impl` and `trait` definitions. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct AssocItem { - pub attrs: Vec, - pub id: NodeId, - pub span: Span, - pub vis: Visibility, - pub ident: Ident, - - pub defaultness: Defaultness, - pub generics: Generics, - pub kind: AssocItemKind, - /// See `Item::tokens` for what this is. - pub tokens: Option, -} - -/// Represents various kinds of content within an `impl`. -/// -/// The term "provided" in the variants below refers to the item having a default -/// definition / body. Meanwhile, a "required" item lacks a definition / body. -/// In an implementation, all items must be provided. -/// The `Option`s below denote the bodies, where `Some(_)` -/// means "provided" and conversely `None` means "required". -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub enum AssocItemKind { - /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`. - /// If `def` is parsed, then the associated constant is provided, and otherwise required. - Const(P, Option>), - - /// An associated function. - Fn(FnSig, Option>), - - /// An associated type. - TyAlias(GenericBounds, Option>), - - /// A macro expanding to an associated item. - Macro(Mac), -} - #[derive( Clone, Copy, @@ -1911,7 +1881,7 @@ pub enum TyKind { /// Inferred type of a `self` or `&self` argument in a method. ImplicitSelf, /// A macro in the type position. - Mac(Mac), + MacCall(MacCall), /// Placeholder for a kind that has failed to be defined. Err, /// Placeholder for a `va_list`. @@ -2076,7 +2046,7 @@ impl Param { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct FnDecl { pub inputs: Vec, - pub output: FunctionRetTy, + pub output: FnRetTy, } impl FnDecl { @@ -2119,7 +2089,7 @@ impl Async { if let Async::Yes { .. } = self { true } else { false } } - /// In ths case this is an `async` return, the `NodeId` for the generated `impl Trait` item. + /// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item. pub fn opt_return_id(self) -> Option { match self { Async::Yes { return_impl_trait_id, .. } => Some(return_impl_trait_id), @@ -2139,7 +2109,7 @@ pub enum Const { /// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532). #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub enum Defaultness { - Default, + Default(Span), Final, } @@ -2148,21 +2118,20 @@ pub enum ImplPolarity { /// `impl Trait for Type` Positive, /// `impl !Trait for Type` - Negative, + Negative(Span), } impl fmt::Debug for ImplPolarity { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { ImplPolarity::Positive => "positive".fmt(f), - ImplPolarity::Negative => "negative".fmt(f), + ImplPolarity::Negative(_) => "negative".fmt(f), } } } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub enum FunctionRetTy { - // FIXME(Centril): Rename to `FnRetTy` and in HIR also. +pub enum FnRetTy { /// Returns type is not specified. /// /// Functions default to `()` and closures default to inference. @@ -2172,11 +2141,11 @@ pub enum FunctionRetTy { Ty(P), } -impl FunctionRetTy { +impl FnRetTy { pub fn span(&self) -> Span { match *self { - FunctionRetTy::Default(span) => span, - FunctionRetTy::Ty(ref ty) => ty.span, + FnRetTy::Default(span) => span, + FnRetTy::Ty(ref ty) => ty.span, } } } @@ -2184,7 +2153,7 @@ impl FunctionRetTy { /// Module declaration. /// /// E.g., `mod foo;` or `mod foo { .. }`. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Default)] pub struct Mod { /// A span from the first token past `{` to the last token until `}`. /// For `mod foo;`, the inner span ranges from the first token @@ -2445,15 +2414,15 @@ impl VariantData { } } -/// An item. -/// -/// The name might be a dummy name in case of anonymous items. +/// An item definition. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Item { pub attrs: Vec, pub id: NodeId, pub span: Span, pub vis: Visibility, + /// The name of the item. + /// It might be a dummy name in case of anonymous items. pub ident: Ident, pub kind: K, @@ -2475,6 +2444,13 @@ impl Item { } } +impl> Item { + pub fn into_item(self) -> Item { + let Item { attrs, id, span, vis, ident, kind, tokens } = self; + Item { attrs, id, span, vis, ident, kind: kind.into(), tokens } + } +} + /// `extern` qualifier on a function item or function type. #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] pub enum Extern { @@ -2536,15 +2512,15 @@ pub enum ItemKind { /// A static item (`static`). /// /// E.g., `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`. - Static(P, Mutability, P), + Static(P, Mutability, Option>), /// A constant item (`const`). /// /// E.g., `const FOO: i32 = 42;`. - Const(P, P), + Const(Defaultness, P, Option>), /// A function declaration (`fn`). /// /// E.g., `fn foo(bar: usize) -> usize { .. }`. - Fn(FnSig, Generics, Option>), + Fn(Defaultness, FnSig, Generics, Option>), /// A module declaration (`mod`). /// /// E.g., `mod foo;` or `mod foo { .. }`. @@ -2558,7 +2534,7 @@ pub enum ItemKind { /// A type alias (`type`). /// /// E.g., `type Foo = Bar;`. - TyAlias(P, Generics), + TyAlias(Defaultness, Generics, GenericBounds, Option>), /// An enum definition (`enum`). /// /// E.g., `enum Foo { C, D }`. @@ -2598,37 +2574,48 @@ pub enum ItemKind { /// A macro invocation. /// /// E.g., `foo!(..)`. - Mac(Mac), + MacCall(MacCall), /// A macro definition. MacroDef(MacroDef), } impl ItemKind { - pub fn descriptive_variant(&self) -> &str { - match *self { + pub fn article(&self) -> &str { + use ItemKind::*; + match self { + Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..) + | Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..) => "a", + ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an", + } + } + + pub fn descr(&self) -> &str { + match self { ItemKind::ExternCrate(..) => "extern crate", - ItemKind::Use(..) => "use", + ItemKind::Use(..) => "`use` import", ItemKind::Static(..) => "static item", ItemKind::Const(..) => "constant item", ItemKind::Fn(..) => "function", ItemKind::Mod(..) => "module", - ItemKind::ForeignMod(..) => "foreign module", - ItemKind::GlobalAsm(..) => "global asm", + ItemKind::ForeignMod(..) => "extern block", + ItemKind::GlobalAsm(..) => "global asm item", ItemKind::TyAlias(..) => "type alias", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", ItemKind::Union(..) => "union", ItemKind::Trait(..) => "trait", ItemKind::TraitAlias(..) => "trait alias", - ItemKind::Mac(..) | ItemKind::MacroDef(..) | ItemKind::Impl { .. } => "item", + ItemKind::MacCall(..) => "item macro invocation", + ItemKind::MacroDef(..) => "macro definition", + ItemKind::Impl { .. } => "implementation", } } pub fn generics(&self) -> Option<&Generics> { match self { - Self::Fn(_, generics, _) - | Self::TyAlias(_, generics) + Self::Fn(_, _, generics, _) + | Self::TyAlias(_, generics, ..) | Self::Enum(_, generics) | Self::Struct(_, generics) | Self::Union(_, generics) @@ -2640,28 +2627,100 @@ impl ItemKind { } } -pub type ForeignItem = Item; +/// Represents associated items. +/// These include items in `impl` and `trait` definitions. +pub type AssocItem = Item; -/// An item within an `extern` block. +/// Represents associated item kinds. +/// +/// The term "provided" in the variants below refers to the item having a default +/// definition / body. Meanwhile, a "required" item lacks a definition / body. +/// In an implementation, all items must be provided. +/// The `Option`s below denote the bodies, where `Some(_)` +/// means "provided" and conversely `None` means "required". +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub enum AssocItemKind { + /// An associated constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`. + /// If `def` is parsed, then the constant is provided, and otherwise required. + Const(Defaultness, P, Option>), + /// An associated function. + Fn(Defaultness, FnSig, Generics, Option>), + /// An associated type. + TyAlias(Defaultness, Generics, GenericBounds, Option>), + /// A macro expanding to associated items. + MacCall(MacCall), +} + +impl AssocItemKind { + pub fn defaultness(&self) -> Defaultness { + match *self { + Self::Const(def, ..) | Self::Fn(def, ..) | Self::TyAlias(def, ..) => def, + Self::MacCall(..) => Defaultness::Final, + } + } +} + +impl From for ItemKind { + fn from(assoc_item_kind: AssocItemKind) -> ItemKind { + match assoc_item_kind { + AssocItemKind::Const(a, b, c) => ItemKind::Const(a, b, c), + AssocItemKind::Fn(a, b, c, d) => ItemKind::Fn(a, b, c, d), + AssocItemKind::TyAlias(a, b, c, d) => ItemKind::TyAlias(a, b, c, d), + AssocItemKind::MacCall(a) => ItemKind::MacCall(a), + } + } +} + +impl TryFrom for AssocItemKind { + type Error = ItemKind; + + fn try_from(item_kind: ItemKind) -> Result { + Ok(match item_kind { + ItemKind::Const(a, b, c) => AssocItemKind::Const(a, b, c), + ItemKind::Fn(a, b, c, d) => AssocItemKind::Fn(a, b, c, d), + ItemKind::TyAlias(a, b, c, d) => AssocItemKind::TyAlias(a, b, c, d), + ItemKind::MacCall(a) => AssocItemKind::MacCall(a), + _ => return Err(item_kind), + }) + } +} + +/// An item in `extern` block. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum ForeignItemKind { + /// A foreign static item (`static FOO: u8`). + Static(P, Mutability, Option>), /// A foreign function. - Fn(FnSig, Generics, Option>), - /// A foreign static item (`static ext: u8`). - Static(P, Mutability), + Fn(Defaultness, FnSig, Generics, Option>), /// A foreign type. - Ty, - /// A macro invocation. - Macro(Mac), + TyAlias(Defaultness, Generics, GenericBounds, Option>), + /// A macro expanding to foreign items. + MacCall(MacCall), +} + +impl From for ItemKind { + fn from(foreign_item_kind: ForeignItemKind) -> ItemKind { + match foreign_item_kind { + ForeignItemKind::Static(a, b, c) => ItemKind::Static(a, b, c), + ForeignItemKind::Fn(a, b, c, d) => ItemKind::Fn(a, b, c, d), + ForeignItemKind::TyAlias(a, b, c, d) => ItemKind::TyAlias(a, b, c, d), + ForeignItemKind::MacCall(a) => ItemKind::MacCall(a), + } + } } -impl ForeignItemKind { - pub fn descriptive_variant(&self) -> &str { - match *self { - ForeignItemKind::Fn(..) => "foreign function", - ForeignItemKind::Static(..) => "foreign static item", - ForeignItemKind::Ty => "foreign type", - ForeignItemKind::Macro(..) => "macro in foreign module", - } +impl TryFrom for ForeignItemKind { + type Error = ItemKind; + + fn try_from(item_kind: ItemKind) -> Result { + Ok(match item_kind { + ItemKind::Static(a, b, c) => ForeignItemKind::Static(a, b, c), + ItemKind::Fn(a, b, c, d) => ForeignItemKind::Fn(a, b, c, d), + ItemKind::TyAlias(a, b, c, d) => ForeignItemKind::TyAlias(a, b, c, d), + ItemKind::MacCall(a) => ForeignItemKind::MacCall(a), + _ => return Err(item_kind), + }) } } + +pub type ForeignItem = Item; diff --git a/src/libsyntax/ast/tests.rs b/src/librustc_ast/ast/tests.rs similarity index 100% rename from src/libsyntax/ast/tests.rs rename to src/librustc_ast/ast/tests.rs diff --git a/src/libsyntax/attr/mod.rs b/src/librustc_ast/attr/mod.rs similarity index 97% rename from src/libsyntax/attr/mod.rs rename to src/librustc_ast/attr/mod.rs index 313f5269235..249311851fb 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/librustc_ast/attr/mod.rs @@ -286,6 +286,10 @@ impl MetaItem { } impl AttrItem { + pub fn span(&self) -> Span { + self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) + } + pub fn meta(&self, span: Span) -> Option { Some(MetaItem { path: self.path.clone(), @@ -437,7 +441,7 @@ impl MetaItem { I: Iterator, { // FIXME: Share code with `parse_path`. - let path = match tokens.next() { + let path = match tokens.next().map(TokenTree::uninterpolate) { Some(TokenTree::Token(Token { kind: kind @ token::Ident(..), span })) | Some(TokenTree::Token(Token { kind: kind @ token::ModSep, span })) => 'arm: { let mut segments = if let token::Ident(name, _) = kind { @@ -453,7 +457,7 @@ impl MetaItem { }; loop { if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span })) = - tokens.next() + tokens.next().map(TokenTree::uninterpolate) { segments.push(PathSegment::from_ident(Ident::new(name, span))); } else { @@ -470,7 +474,6 @@ impl MetaItem { Path { span, segments } } Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { - token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident), token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span), token::Nonterminal::NtPath(ref path) => path.clone(), _ => return None, @@ -529,7 +532,7 @@ impl MetaItemKind { TokenTree::Delimited( DelimSpan::from_single(span), token::Paren, - TokenStream::new(tokens).into(), + TokenStream::new(tokens), ) .into(), ] @@ -674,9 +677,9 @@ impl HasAttrs for StmtKind { fn attrs(&self) -> &[Attribute] { match *self { StmtKind::Local(ref local) => local.attrs(), - StmtKind::Item(..) => &[], StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(), - StmtKind::Mac(ref mac) => { + StmtKind::Empty | StmtKind::Item(..) => &[], + StmtKind::MacCall(ref mac) => { let (_, _, ref attrs) = **mac; attrs.attrs() } @@ -686,10 +689,9 @@ impl HasAttrs for StmtKind { fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec)) { match self { StmtKind::Local(local) => local.visit_attrs(f), - StmtKind::Item(..) => {} - StmtKind::Expr(expr) => expr.visit_attrs(f), - StmtKind::Semi(expr) => expr.visit_attrs(f), - StmtKind::Mac(mac) => { + StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), + StmtKind::Empty | StmtKind::Item(..) => {} + StmtKind::MacCall(mac) => { let (_mac, _style, attrs) = mac.deref_mut(); attrs.visit_attrs(f); } @@ -722,6 +724,6 @@ macro_rules! derive_has_attrs { } derive_has_attrs! { - Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::AssocItem, ast::Arm, + Item, Expr, Local, ast::AssocItem, ast::ForeignItem, ast::StructField, ast::Arm, ast::Field, ast::FieldPat, ast::Variant, ast::Param, GenericParam } diff --git a/src/libsyntax/build.rs b/src/librustc_ast/build.rs similarity index 100% rename from src/libsyntax/build.rs rename to src/librustc_ast/build.rs diff --git a/src/libsyntax/entry.rs b/src/librustc_ast/entry.rs similarity index 100% rename from src/libsyntax/entry.rs rename to src/librustc_ast/entry.rs diff --git a/src/libsyntax/expand/allocator.rs b/src/librustc_ast/expand/allocator.rs similarity index 100% rename from src/libsyntax/expand/allocator.rs rename to src/librustc_ast/expand/allocator.rs diff --git a/src/libsyntax/expand/mod.rs b/src/librustc_ast/expand/mod.rs similarity index 100% rename from src/libsyntax/expand/mod.rs rename to src/librustc_ast/expand/mod.rs diff --git a/src/libsyntax/lib.rs b/src/librustc_ast/lib.rs similarity index 96% rename from src/libsyntax/lib.rs rename to src/librustc_ast/lib.rs index adb96356aae..2594cc536ac 100644 --- a/src/libsyntax/lib.rs +++ b/src/librustc_ast/lib.rs @@ -7,7 +7,9 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] #![feature(bool_to_option)] #![feature(box_syntax)] +#![feature(const_if_match)] #![feature(const_fn)] // For the `transmute` in `P::new` +#![feature(const_panic)] #![feature(const_transmute)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] diff --git a/src/libsyntax/mut_visit.rs b/src/librustc_ast/mut_visit.rs similarity index 94% rename from src/libsyntax/mut_visit.rs rename to src/librustc_ast/mut_visit.rs index e0180d45193..aa2968b3cbe 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/librustc_ast/mut_visit.rs @@ -202,7 +202,7 @@ pub trait MutVisitor: Sized { noop_visit_local(l, self); } - fn visit_mac(&mut self, _mac: &mut Mac) { + fn visit_mac(&mut self, _mac: &mut MacCall) { panic!("visit_mac disabled by default"); // N.B., see note about macros above. If you really want a visitor that // works on macros, use this definition in your trait impl: @@ -482,7 +482,7 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { vis.visit_id(id); visit_vec(bounds, |bound| vis.visit_param_bound(bound)); } - TyKind::Mac(mac) => vis.visit_mac(mac), + TyKind::MacCall(mac) => vis.visit_mac(mac), } vis.visit_span(span); } @@ -584,14 +584,14 @@ pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_mac(mac: &mut Mac, vis: &mut T) { - let Mac { path, args, prior_type_ascription: _ } = mac; +pub fn noop_visit_mac(mac: &mut MacCall, vis: &mut T) { + let MacCall { path, args, prior_type_ascription: _ } = mac; vis.visit_path(path); visit_mac_args(args, vis); } pub fn noop_visit_macro_def(macro_def: &mut MacroDef, vis: &mut T) { - let MacroDef { body, legacy: _ } = macro_def; + let MacroDef { body, macro_rules: _ } = macro_def; visit_mac_args(body, vis); } @@ -711,20 +711,7 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: } token::NtPath(path) => vis.visit_path(path), token::NtTT(tt) => vis.visit_tt(tt), - token::NtImplItem(item) => visit_clobber(item, |item| { - // See reasoning above. - vis.flat_map_impl_item(item).expect_one("expected visitor to produce exactly one item") - }), - token::NtTraitItem(item) => visit_clobber(item, |item| { - // See reasoning above. - vis.flat_map_trait_item(item).expect_one("expected visitor to produce exactly one item") - }), token::NtVis(visib) => vis.visit_vis(visib), - token::NtForeignItem(item) => visit_clobber(item, |item| { - // See reasoning above. - vis.flat_map_foreign_item(item) - .expect_one("expected visitor to produce exactly one item") - }), } } @@ -744,10 +731,10 @@ pub fn noop_visit_fn_decl(decl: &mut P, vis: &mut T) { noop_visit_fn_ret_ty(output, vis); } -pub fn noop_visit_fn_ret_ty(fn_ret_ty: &mut FunctionRetTy, vis: &mut T) { +pub fn noop_visit_fn_ret_ty(fn_ret_ty: &mut FnRetTy, vis: &mut T) { match fn_ret_ty { - FunctionRetTy::Default(span) => vis.visit_span(span), - FunctionRetTy::Ty(ty) => vis.visit_ty(ty), + FnRetTy::Default(span) => vis.visit_span(span), + FnRetTy::Ty(ty) => vis.visit_ty(ty), } } @@ -890,15 +877,11 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { match kind { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(ty, _mut, expr) => { - vis.visit_ty(ty); - vis.visit_expr(expr); - } - ItemKind::Const(ty, expr) => { + ItemKind::Static(ty, _, expr) | ItemKind::Const(_, ty, expr) => { vis.visit_ty(ty); - vis.visit_expr(expr); + visit_opt(expr, |expr| vis.visit_expr(expr)); } - ItemKind::Fn(sig, generics, body) => { + ItemKind::Fn(_, sig, generics, body) => { visit_fn_sig(sig, vis); vis.visit_generics(generics); visit_opt(body, |body| vis.visit_block(body)); @@ -906,9 +889,10 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { ItemKind::Mod(m) => vis.visit_mod(m), ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), ItemKind::GlobalAsm(_ga) => {} - ItemKind::TyAlias(ty, generics) => { - vis.visit_ty(ty); + ItemKind::TyAlias(_, generics, bounds, ty) => { vis.visit_generics(generics); + visit_bounds(bounds, vis); + visit_opt(ty, |ty| vis.visit_ty(ty)); } ItemKind::Enum(EnumDef { variants }, generics) => { variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); @@ -942,7 +926,7 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { vis.visit_generics(generics); visit_bounds(bounds, vis); } - ItemKind::Mac(m) => vis.visit_mac(m), + ItemKind::MacCall(m) => vis.visit_mac(m), ItemKind::MacroDef(def) => vis.visit_macro_def(def), } } @@ -951,30 +935,29 @@ pub fn noop_flat_map_assoc_item( mut item: P, visitor: &mut T, ) -> SmallVec<[P; 1]> { - let AssocItem { id, ident, vis, defaultness: _, attrs, generics, kind, span, tokens: _ } = - item.deref_mut(); + let Item { id, ident, vis, attrs, kind, span, tokens: _ } = item.deref_mut(); visitor.visit_id(id); visitor.visit_ident(ident); visitor.visit_vis(vis); visit_attrs(attrs, visitor); - visitor.visit_generics(generics); match kind { - AssocItemKind::Const(ty, expr) => { + AssocItemKind::Const(_, ty, expr) => { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } - AssocItemKind::Fn(sig, body) => { + AssocItemKind::Fn(_, sig, generics, body) => { + visitor.visit_generics(generics); visit_fn_sig(sig, visitor); visit_opt(body, |body| visitor.visit_block(body)); } - AssocItemKind::TyAlias(bounds, ty) => { + AssocItemKind::TyAlias(_, generics, bounds, ty) => { + visitor.visit_generics(generics); visit_bounds(bounds, visitor); visit_opt(ty, |ty| visitor.visit_ty(ty)); } - AssocItemKind::Macro(mac) => visitor.visit_mac(mac), + AssocItemKind::MacCall(mac) => visitor.visit_mac(mac), } visitor.visit_span(span); - smallvec![item] } @@ -989,7 +972,7 @@ pub fn noop_visit_mod(Mod { inner, items, inline: _ }: &mut Mod, } pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { - visit_clobber(krate, |Crate { module, attrs, span }| { + visit_clobber(krate, |Crate { module, attrs, span, proc_macros }| { let item = P(Item { ident: Ident::invalid(), attrs, @@ -1004,11 +987,11 @@ pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { let len = items.len(); if len == 0 { let module = Mod { inner: span, items: vec![], inline: true }; - Crate { module, attrs: vec![], span } + Crate { module, attrs: vec![], span, proc_macros } } else if len == 1 { let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner(); match kind { - ItemKind::Mod(module) => Crate { module, attrs, span }, + ItemKind::Mod(module) => Crate { module, attrs, span, proc_macros }, _ => panic!("visitor converted a module to not a module"), } } else { @@ -1040,23 +1023,29 @@ pub fn noop_flat_map_foreign_item( mut item: P, visitor: &mut T, ) -> SmallVec<[P; 1]> { - let ForeignItem { ident, attrs, id, kind, vis, span, tokens: _ } = item.deref_mut(); + let Item { ident, attrs, id, kind, vis, span, tokens: _ } = item.deref_mut(); + visitor.visit_id(id); visitor.visit_ident(ident); + visitor.visit_vis(vis); visit_attrs(attrs, visitor); match kind { - ForeignItemKind::Fn(sig, generics, body) => { - visit_fn_sig(sig, visitor); + ForeignItemKind::Static(ty, _, expr) => { + visitor.visit_ty(ty); + visit_opt(expr, |expr| visitor.visit_expr(expr)); + } + ForeignItemKind::Fn(_, sig, generics, body) => { visitor.visit_generics(generics); + visit_fn_sig(sig, visitor); visit_opt(body, |body| visitor.visit_block(body)); } - ForeignItemKind::Static(t, _m) => visitor.visit_ty(t), - ForeignItemKind::Ty => {} - ForeignItemKind::Macro(mac) => visitor.visit_mac(mac), + ForeignItemKind::TyAlias(_, generics, bounds, ty) => { + visitor.visit_generics(generics); + visit_bounds(bounds, visitor); + visit_opt(ty, |ty| visitor.visit_ty(ty)); + } + ForeignItemKind::MacCall(mac) => visitor.visit_mac(mac), } - visitor.visit_id(id); visitor.visit_span(span); - visitor.visit_vis(vis); - smallvec![item] } @@ -1093,7 +1082,7 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { visit_vec(elems, |elem| vis.visit_pat(elem)) } PatKind::Paren(inner) => vis.visit_pat(inner), - PatKind::Mac(mac) => vis.visit_mac(mac), + PatKind::MacCall(mac) => vis.visit_mac(mac), } vis.visit_span(span); } @@ -1230,7 +1219,7 @@ pub fn noop_visit_expr(Expr { kind, id, span, attrs }: &mut Expr, } visit_vec(inputs, |(_c, expr)| vis.visit_expr(expr)); } - ExprKind::Mac(mac) => vis.visit_mac(mac), + ExprKind::MacCall(mac) => vis.visit_mac(mac), ExprKind::Struct(path, fields, expr) => { vis.visit_path(path); fields.flat_map_in_place(|field| vis.flat_map_field(field)); @@ -1285,11 +1274,12 @@ pub fn noop_flat_map_stmt_kind( StmtKind::Item(item) => vis.flat_map_item(item).into_iter().map(StmtKind::Item).collect(), StmtKind::Expr(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Expr).collect(), StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(), - StmtKind::Mac(mut mac) => { + StmtKind::Empty => smallvec![StmtKind::Empty], + StmtKind::MacCall(mut mac) => { let (mac_, _semi, attrs) = mac.deref_mut(); vis.visit_mac(mac_); visit_thin_attrs(attrs, vis); - smallvec![StmtKind::Mac(mac)] + smallvec![StmtKind::MacCall(mac)] } } } diff --git a/src/libsyntax/node_id.rs b/src/librustc_ast/node_id.rs similarity index 95% rename from src/libsyntax/node_id.rs rename to src/librustc_ast/node_id.rs index 58d2334a7b1..cd562c48e91 100644 --- a/src/libsyntax/node_id.rs +++ b/src/librustc_ast/node_id.rs @@ -12,7 +12,7 @@ rustc_index::newtype_index! { rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeId); /// `NodeId` used to represent the root of the crate. -pub const CRATE_NODE_ID: NodeId = NodeId::from_u32_const(0); +pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0); /// When parsing and doing expansions, we initially give all AST nodes this AST /// node value. Then later, in the renumber pass, we renumber them to have diff --git a/src/libsyntax/ptr.rs b/src/librustc_ast/ptr.rs similarity index 100% rename from src/libsyntax/ptr.rs rename to src/librustc_ast/ptr.rs diff --git a/src/libsyntax/token.rs b/src/librustc_ast/token.rs similarity index 81% rename from src/libsyntax/token.rs rename to src/librustc_ast/token.rs index 862934300e0..3fc6444168e 100644 --- a/src/libsyntax/token.rs +++ b/src/librustc_ast/token.rs @@ -14,8 +14,8 @@ use rustc_macros::HashStable_Generic; use rustc_span::symbol::kw; use rustc_span::symbol::Symbol; use rustc_span::{self, Span, DUMMY_SP}; -use std::fmt; -use std::mem; +use std::borrow::Cow; +use std::{fmt, mem}; #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] #[derive(HashStable_Generic)] @@ -147,36 +147,30 @@ impl Lit { pub fn ident_can_begin_expr(name: ast::Name, span: Span, is_raw: bool) -> bool { let ident_token = Token::new(Ident(name, is_raw), span); - token_can_begin_expr(&ident_token) -} -pub fn token_can_begin_expr(ident_token: &Token) -> bool { !ident_token.is_reserved_ident() || ident_token.is_path_segment_keyword() - || match ident_token.kind { - TokenKind::Ident(ident, _) => [ - kw::Async, - kw::Do, - kw::Box, - kw::Break, - kw::Continue, - kw::False, - kw::For, - kw::If, - kw::Let, - kw::Loop, - kw::Match, - kw::Move, - kw::Return, - kw::True, - kw::Unsafe, - kw::While, - kw::Yield, - kw::Static, - ] - .contains(&ident), - _ => false, - } + || [ + kw::Async, + kw::Do, + kw::Box, + kw::Break, + kw::Continue, + kw::False, + kw::For, + kw::If, + kw::Let, + kw::Loop, + kw::Match, + kw::Move, + kw::Return, + kw::True, + kw::Unsafe, + kw::While, + kw::Yield, + kw::Static, + ] + .contains(&name) } fn ident_can_begin_type(name: ast::Name, span: Span, is_raw: bool) -> bool { @@ -231,8 +225,15 @@ pub enum TokenKind { /* Literals */ Literal(Lit), - /* Name components */ + /// Identifier token. + /// Do not forget about `NtIdent` when you want to match on identifiers. + /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to + /// treat regular and interpolated identifiers in the same way. Ident(ast::Name, /* is_raw */ bool), + /// Lifetime identifier token. + /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers. + /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to + /// treat regular and interpolated lifetime identifiers in the same way. Lifetime(ast::Name), Interpolated(Lrc), @@ -270,6 +271,39 @@ impl TokenKind { Literal(Lit::new(kind, symbol, suffix)) } + // An approximation to proc-macro-style single-character operators used by rustc parser. + // If the operator token can be broken into two tokens, the first of which is single-character, + // then this function performs that operation, otherwise it returns `None`. + pub fn break_two_token_op(&self) -> Option<(TokenKind, TokenKind)> { + Some(match *self { + Le => (Lt, Eq), + EqEq => (Eq, Eq), + Ne => (Not, Eq), + Ge => (Gt, Eq), + AndAnd => (BinOp(And), BinOp(And)), + OrOr => (BinOp(Or), BinOp(Or)), + BinOp(Shl) => (Lt, Lt), + BinOp(Shr) => (Gt, Gt), + BinOpEq(Plus) => (BinOp(Plus), Eq), + BinOpEq(Minus) => (BinOp(Minus), Eq), + BinOpEq(Star) => (BinOp(Star), Eq), + BinOpEq(Slash) => (BinOp(Slash), Eq), + BinOpEq(Percent) => (BinOp(Percent), Eq), + BinOpEq(Caret) => (BinOp(Caret), Eq), + BinOpEq(And) => (BinOp(And), Eq), + BinOpEq(Or) => (BinOp(Or), Eq), + BinOpEq(Shl) => (Lt, Le), + BinOpEq(Shr) => (Gt, Ge), + DotDot => (Dot, Dot), + DotDotDot => (Dot, DotDot), + ModSep => (Colon, Colon), + RArrow => (BinOp(Minus), Gt), + LArrow => (Lt, BinOp(Minus)), + FatArrow => (Eq, Gt), + _ => return None, + }) + } + /// Returns tokens that are likely to be typed accidentally instead of the current token. /// Enables better error recovery when the wrong token is found. pub fn similar_tokens(&self) -> Option> { @@ -301,6 +335,19 @@ impl Token { mem::replace(self, Token::dummy()) } + /// For interpolated tokens, returns a span of the fragment to which the interpolated + /// token refers. For all other tokens this is just a regular span. + /// It is particularly important to use this for identifiers and lifetimes + /// for which spans affect name resolution and edition checks. + /// Note that keywords are also identifiers, so they should use this + /// if they keep spans or perform edition checks. + pub fn uninterpolated_span(&self) -> Span { + match &self.kind { + Interpolated(nt) => nt.span(), + _ => self.span, + } + } + pub fn is_op(&self) -> bool { match self.kind { OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) @@ -318,7 +365,7 @@ impl Token { /// Returns `true` if the token can appear at the start of an expression. pub fn can_begin_expr(&self) -> bool { - match self.kind { + match self.uninterpolate().kind { Ident(name, is_raw) => ident_can_begin_expr(name, self.span, is_raw), // value name or keyword OpenDelim(..) | // tuple, array or block @@ -337,11 +384,9 @@ impl Token { Pound => true, // expression attributes Interpolated(ref nt) => match **nt { NtLiteral(..) | - NtIdent(..) | NtExpr(..) | NtBlock(..) | - NtPath(..) | - NtLifetime(..) => true, + NtPath(..) => true, _ => false, }, _ => false, @@ -350,7 +395,7 @@ impl Token { /// Returns `true` if the token can appear at the start of a type. pub fn can_begin_type(&self) -> bool { - match self.kind { + match self.uninterpolate().kind { Ident(name, is_raw) => ident_can_begin_type(name, self.span, is_raw), // type name or keyword OpenDelim(Paren) | // tuple @@ -364,7 +409,7 @@ impl Token { Lt | BinOp(Shl) | // associated path ModSep => true, // global path Interpolated(ref nt) => match **nt { - NtIdent(..) | NtTy(..) | NtPath(..) | NtLifetime(..) => true, + NtTy(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -405,7 +450,7 @@ impl Token { /// /// Keep this in sync with `Lit::from_token`. pub fn can_begin_literal_or_bool(&self) -> bool { - match self.kind { + match self.uninterpolate().kind { Literal(..) | BinOp(Minus) => true, Ident(name, false) if name.is_bool_lit() => true, Interpolated(ref nt) => match &**nt { @@ -416,26 +461,37 @@ impl Token { } } + // A convenience function for matching on identifiers during parsing. + // Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token + // into the regular identifier or lifetime token it refers to, + // otherwise returns the original token. + pub fn uninterpolate(&self) -> Cow<'_, Token> { + match &self.kind { + Interpolated(nt) => match **nt { + NtIdent(ident, is_raw) => { + Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)) + } + NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)), + _ => Cow::Borrowed(self), + }, + _ => Cow::Borrowed(self), + } + } + /// Returns an identifier if this token is an identifier. pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> { - match self.kind { - Ident(name, is_raw) => Some((ast::Ident::new(name, self.span), is_raw)), - Interpolated(ref nt) => match **nt { - NtIdent(ident, is_raw) => Some((ident, is_raw)), - _ => None, - }, + let token = self.uninterpolate(); + match token.kind { + Ident(name, is_raw) => Some((ast::Ident::new(name, token.span), is_raw)), _ => None, } } /// Returns a lifetime identifier if this token is a lifetime. pub fn lifetime(&self) -> Option { - match self.kind { - Lifetime(name) => Some(ast::Ident::new(name, self.span)), - Interpolated(ref nt) => match **nt { - NtLifetime(ident) => Some(ident), - _ => None, - }, + let token = self.uninterpolate(); + match token.kind { + Lifetime(name) => Some(ast::Ident::new(name, token.span)), _ => None, } } @@ -479,6 +535,16 @@ impl Token { false } + // Is the token an interpolated block (`$b:block`)? + pub fn is_whole_block(&self) -> bool { + if let Interpolated(ref nt) = self.kind { + if let NtBlock(..) = **nt { + return true; + } + } + false + } + /// Returns `true` if the token is either the `mut` or `const` keyword. pub fn is_mutability(&self) -> bool { self.is_keyword(kw::Mut) || self.is_keyword(kw::Const) @@ -679,18 +745,30 @@ pub enum Nonterminal { NtPath(ast::Path), NtVis(ast::Visibility), NtTT(TokenTree), - // Used only for passing items to proc macro attributes (they are not - // strictly necessary for that, `Annotatable` can be converted into - // tokens directly, but doing that naively regresses pretty-printing). - NtTraitItem(P), - NtImplItem(P), - NtForeignItem(P), } // `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] rustc_data_structures::static_assert_size!(Nonterminal, 40); +impl Nonterminal { + fn span(&self) -> Span { + match self { + NtItem(item) => item.span, + NtBlock(block) => block.span, + NtStmt(stmt) => stmt.span, + NtPat(pat) => pat.span, + NtExpr(expr) | NtLiteral(expr) => expr.span, + NtTy(ty) => ty.span, + NtIdent(ident, _) | NtLifetime(ident) => ident.span, + NtMeta(attr_item) => attr_item.span(), + NtPath(path) => path.span, + NtVis(vis) => vis.span, + NtTT(tt) => tt.span(), + } + } +} + impl PartialEq for Nonterminal { fn eq(&self, rhs: &Self) -> bool { match (self, rhs) { @@ -722,9 +800,6 @@ impl fmt::Debug for Nonterminal { NtMeta(..) => f.pad("NtMeta(..)"), NtPath(..) => f.pad("NtPath(..)"), NtTT(..) => f.pad("NtTT(..)"), - NtImplItem(..) => f.pad("NtImplItem(..)"), - NtTraitItem(..) => f.pad("NtTraitItem(..)"), - NtForeignItem(..) => f.pad("NtForeignItem(..)"), NtVis(..) => f.pad("NtVis(..)"), NtLifetime(..) => f.pad("NtLifetime(..)"), } diff --git a/src/libsyntax/tokenstream.rs b/src/librustc_ast/tokenstream.rs similarity index 98% rename from src/libsyntax/tokenstream.rs rename to src/librustc_ast/tokenstream.rs index 03e8fff247b..916a5ff6f46 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/librustc_ast/tokenstream.rs @@ -116,6 +116,13 @@ impl TokenTree { pub fn close_tt(span: DelimSpan, delim: DelimToken) -> TokenTree { TokenTree::token(token::CloseDelim(delim), span.close) } + + pub fn uninterpolate(self) -> TokenTree { + match self { + TokenTree::Token(token) => TokenTree::Token(token.uninterpolate().into_owned()), + tt => tt, + } + } } impl HashStable for TokenStream diff --git a/src/libsyntax/util/classify.rs b/src/librustc_ast/util/classify.rs similarity index 100% rename from src/libsyntax/util/classify.rs rename to src/librustc_ast/util/classify.rs diff --git a/src/libsyntax/util/comments.rs b/src/librustc_ast/util/comments.rs similarity index 98% rename from src/libsyntax/util/comments.rs rename to src/librustc_ast/util/comments.rs index 5a67531624d..0e42ae11fa2 100644 --- a/src/libsyntax/util/comments.rs +++ b/src/librustc_ast/util/comments.rs @@ -189,8 +189,8 @@ fn split_block_comment_into_lines(text: &str, col: CharPos) -> Vec { // it appears this function is called only from pprust... that's // probably not a good thing. pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec { - let cm = SourceMap::new(sm.path_mapping().clone()); - let source_file = cm.new_source_file(path, src); + let sm = SourceMap::new(sm.path_mapping().clone()); + let source_file = sm.new_source_file(path, src); let text = (*source_file.src.as_ref().unwrap()).clone(); let text: &str = text.as_str(); diff --git a/src/libsyntax/util/comments/tests.rs b/src/librustc_ast/util/comments/tests.rs similarity index 100% rename from src/libsyntax/util/comments/tests.rs rename to src/librustc_ast/util/comments/tests.rs diff --git a/src/libsyntax/util/lev_distance.rs b/src/librustc_ast/util/lev_distance.rs similarity index 100% rename from src/libsyntax/util/lev_distance.rs rename to src/librustc_ast/util/lev_distance.rs diff --git a/src/libsyntax/util/lev_distance/tests.rs b/src/librustc_ast/util/lev_distance/tests.rs similarity index 100% rename from src/libsyntax/util/lev_distance/tests.rs rename to src/librustc_ast/util/lev_distance/tests.rs diff --git a/src/libsyntax/util/literal.rs b/src/librustc_ast/util/literal.rs similarity index 99% rename from src/libsyntax/util/literal.rs rename to src/librustc_ast/util/literal.rs index 0c611adc06b..d1757394f3a 100644 --- a/src/libsyntax/util/literal.rs +++ b/src/librustc_ast/util/literal.rs @@ -191,7 +191,7 @@ impl Lit { /// /// Keep this in sync with `Token::can_begin_literal_or_bool`. pub fn from_token(token: &Token) -> Result { - let lit = match token.kind { + let lit = match token.uninterpolate().kind { token::Ident(name, false) if name.is_bool_lit() => { token::Lit::new(token::Bool, name, None) } diff --git a/src/libsyntax/util/map_in_place.rs b/src/librustc_ast/util/map_in_place.rs similarity index 100% rename from src/libsyntax/util/map_in_place.rs rename to src/librustc_ast/util/map_in_place.rs diff --git a/src/libsyntax/util/parser.rs b/src/librustc_ast/util/parser.rs similarity index 100% rename from src/libsyntax/util/parser.rs rename to src/librustc_ast/util/parser.rs diff --git a/src/libsyntax/visit.rs b/src/librustc_ast/visit.rs similarity index 92% rename from src/libsyntax/visit.rs rename to src/librustc_ast/visit.rs index 73e731397c3..39028b7583c 100644 --- a/src/libsyntax/visit.rs +++ b/src/librustc_ast/visit.rs @@ -168,7 +168,7 @@ pub trait Visitor<'ast>: Sized { fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) { walk_lifetime(self, lifetime) } - fn visit_mac(&mut self, _mac: &'ast Mac) { + fn visit_mac(&mut self, _mac: &'ast MacCall) { panic!("visit_mac disabled by default"); // N.B., see note about macros above. // if you really want a visitor that @@ -215,7 +215,7 @@ pub trait Visitor<'ast>: Sized { fn visit_vis(&mut self, vis: &'ast Visibility) { walk_vis(self, vis) } - fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FunctionRetTy) { + fn visit_fn_ret_ty(&mut self, ret_ty: &'ast FnRetTy) { walk_fn_ret_ty(self, ret_ty) } fn visit_fn_header(&mut self, _header: &'ast FnHeader) { @@ -298,11 +298,11 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { } } ItemKind::Use(ref use_tree) => visitor.visit_use_tree(use_tree, item.id, false), - ItemKind::Static(ref typ, _, ref expr) | ItemKind::Const(ref typ, ref expr) => { + ItemKind::Static(ref typ, _, ref expr) | ItemKind::Const(_, ref typ, ref expr) => { visitor.visit_ty(typ); - visitor.visit_expr(expr); + walk_list!(visitor, visit_expr, expr); } - ItemKind::Fn(ref sig, ref generics, ref body) => { + ItemKind::Fn(_, ref sig, ref generics, ref body) => { visitor.visit_generics(generics); let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref()); visitor.visit_fn(kind, item.span, item.id) @@ -312,9 +312,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_foreign_item, &foreign_module.items); } ItemKind::GlobalAsm(ref ga) => visitor.visit_global_asm(ga), - ItemKind::TyAlias(ref typ, ref generics) => { - visitor.visit_ty(typ); - visitor.visit_generics(generics) + ItemKind::TyAlias(_, ref generics, ref bounds, ref ty) => { + visitor.visit_generics(generics); + walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_ty, ty); } ItemKind::Enum(ref enum_definition, ref generics) => { visitor.visit_generics(generics); @@ -349,7 +350,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds); } - ItemKind::Mac(ref mac) => visitor.visit_mac(mac), + ItemKind::MacCall(ref mac) => visitor.visit_mac(mac), ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id), } walk_list!(visitor, visit_attribute, &item.attrs); @@ -417,7 +418,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { } TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression), TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} - TyKind::Mac(ref mac) => visitor.visit_mac(mac), + TyKind::MacCall(ref mac) => visitor.visit_mac(mac), TyKind::Never | TyKind::CVarArgs => {} } } @@ -520,26 +521,34 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { PatKind::Tuple(ref elems) | PatKind::Slice(ref elems) | PatKind::Or(ref elems) => { walk_list!(visitor, visit_pat, elems); } - PatKind::Mac(ref mac) => visitor.visit_mac(mac), + PatKind::MacCall(ref mac) => visitor.visit_mac(mac), } } pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignItem) { - visitor.visit_vis(&item.vis); - visitor.visit_ident(item.ident); - - match item.kind { - ForeignItemKind::Fn(ref sig, ref generics, ref body) => { + let Item { id, span, ident, ref vis, ref attrs, ref kind, tokens: _ } = *item; + visitor.visit_vis(vis); + visitor.visit_ident(ident); + walk_list!(visitor, visit_attribute, attrs); + match kind { + ForeignItemKind::Static(ty, _, expr) => { + visitor.visit_ty(ty); + walk_list!(visitor, visit_expr, expr); + } + ForeignItemKind::Fn(_, sig, generics, body) => { visitor.visit_generics(generics); - let kind = FnKind::Fn(FnCtxt::Foreign, item.ident, sig, &item.vis, body.as_deref()); - visitor.visit_fn(kind, item.span, item.id); + let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref()); + visitor.visit_fn(kind, span, id); + } + ForeignItemKind::TyAlias(_, generics, bounds, ty) => { + visitor.visit_generics(generics); + walk_list!(visitor, visit_param_bound, bounds); + walk_list!(visitor, visit_ty, ty); + } + ForeignItemKind::MacCall(mac) => { + visitor.visit_mac(mac); } - ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), - ForeignItemKind::Ty => (), - ForeignItemKind::Macro(ref mac) => visitor.visit_mac(mac), } - - walk_list!(visitor, visit_attribute, &item.attrs); } pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) { @@ -594,8 +603,8 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a } } -pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FunctionRetTy) { - if let FunctionRetTy::Ty(ref output_ty) = *ret_ty { +pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy) { + if let FnRetTy::Ty(ref output_ty) = *ret_ty { visitor.visit_ty(output_ty) } } @@ -622,24 +631,26 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>, _span: Spa } pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem, ctxt: AssocCtxt) { - visitor.visit_vis(&item.vis); - visitor.visit_ident(item.ident); - walk_list!(visitor, visit_attribute, &item.attrs); - visitor.visit_generics(&item.generics); - match item.kind { - AssocItemKind::Const(ref ty, ref expr) => { + let Item { id, span, ident, ref vis, ref attrs, ref kind, tokens: _ } = *item; + visitor.visit_vis(vis); + visitor.visit_ident(ident); + walk_list!(visitor, visit_attribute, attrs); + match kind { + AssocItemKind::Const(_, ty, expr) => { visitor.visit_ty(ty); walk_list!(visitor, visit_expr, expr); } - AssocItemKind::Fn(ref sig, ref body) => { - let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref()); - visitor.visit_fn(kind, item.span, item.id); + AssocItemKind::Fn(_, sig, generics, body) => { + visitor.visit_generics(generics); + let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref()); + visitor.visit_fn(kind, span, id); } - AssocItemKind::TyAlias(ref bounds, ref ty) => { + AssocItemKind::TyAlias(_, generics, bounds, ty) => { + visitor.visit_generics(generics); walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_ty, ty); } - AssocItemKind::Macro(ref mac) => { + AssocItemKind::MacCall(mac) => { visitor.visit_mac(mac); } } @@ -666,10 +677,9 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) { match statement.kind { StmtKind::Local(ref local) => visitor.visit_local(local), StmtKind::Item(ref item) => visitor.visit_item(item), - StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { - visitor.visit_expr(expression) - } - StmtKind::Mac(ref mac) => { + StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr), + StmtKind::Empty => {} + StmtKind::MacCall(ref mac) => { let (ref mac, _, ref attrs) = **mac; visitor.visit_mac(mac); for attr in attrs.iter() { @@ -679,7 +689,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) { } } -pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a Mac) { +pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a MacCall) { visitor.visit_path(&mac.path, DUMMY_NODE_ID); } @@ -801,7 +811,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Ret(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); } - ExprKind::Mac(ref mac) => visitor.visit_mac(mac), + ExprKind::MacCall(ref mac) => visitor.visit_mac(mac), ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression), ExprKind::InlineAsm(ref ia) => { for &(_, ref input) in &ia.inputs { diff --git a/src/librustc_ast_lowering/Cargo.toml b/src/librustc_ast_lowering/Cargo.toml index f6ab60e199f..23dc80facae 100644 --- a/src/librustc_ast_lowering/Cargo.toml +++ b/src/librustc_ast_lowering/Cargo.toml @@ -20,5 +20,5 @@ rustc_index = { path = "../librustc_index" } rustc_span = { path = "../librustc_span" } rustc_errors = { path = "../librustc_errors" } rustc_session = { path = "../librustc_session" } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index b51d4765583..a4cbae51966 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -1,15 +1,15 @@ use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use rustc::bug; +use rustc_ast::ast::*; +use rustc_ast::attr; +use rustc_ast::ptr::P as AstP; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; use rustc_span::symbol::{sym, Symbol}; -use syntax::ast::*; -use syntax::attr; -use syntax::ptr::P as AstP; impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP]) -> &'hir [hir::Expr<'hir>] { @@ -198,7 +198,7 @@ impl<'hir> LoweringContext<'_, 'hir> { return self.lower_expr_for(e, pat, head, body, opt_label); } ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr), - ExprKind::Mac(_) => panic!("Shouldn't exist here"), + ExprKind::MacCall(_) => panic!("Shouldn't exist here"), }; hir::Expr { @@ -480,8 +480,8 @@ impl<'hir> LoweringContext<'_, 'hir> { body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::ExprKind<'hir> { let output = match ret_ty { - Some(ty) => FunctionRetTy::Ty(ty), - None => FunctionRetTy::Default(span), + Some(ty) => FnRetTy::Ty(ty), + None => FnRetTy::Default(span), }; let ast_decl = FnDecl { inputs: vec![], output }; let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None); @@ -721,7 +721,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: Span, ) -> hir::ExprKind<'hir> { let outer_decl = - FnDecl { inputs: decl.inputs.clone(), output: FunctionRetTy::Default(fn_decl_span) }; + FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; // We need to lower the declaration outside the new scope, because we // have to conserve the state of being inside a loop condition for the // closure argument types. @@ -747,7 +747,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `|x: u8| future_from_generator(|| -> X { ... })`. let body_id = this.lower_fn_body(&outer_decl, |this| { let async_ret_ty = - if let FunctionRetTy::Ty(ty) = &decl.output { Some(ty.clone()) } else { None }; + if let FnRetTy::Ty(ty) = &decl.output { Some(ty.clone()) } else { None }; let async_body = this.make_async_expr( capture_clause, closure_id, @@ -783,7 +783,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e2: Option<&Expr>, lims: RangeLimits, ) -> hir::ExprKind<'hir> { - use syntax::ast::RangeLimits::*; + use rustc_ast::ast::RangeLimits::*; let path = match (e1, e2, lims) { (None, None, HalfOpen) => sym::RangeFull, @@ -831,8 +831,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .last() .cloned() .map(|id| Ok(self.lower_node_id(id))) - .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) - .into(), + .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)), }; hir::Destination { label: destination.map(|(_, label)| label), target_id } } @@ -841,7 +840,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if self.is_in_loop_condition && opt_label.is_none() { hir::Destination { label: None, - target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(), + target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition), } } else { self.lower_loop_destination(opt_label.map(|label| (id, label))) @@ -912,7 +911,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .collect(), asm: asm.asm, asm_str_style: asm.asm_str_style, - clobbers: asm.clobbers.clone().into(), + clobbers: asm.clobbers.clone(), volatile: asm.volatile, alignstack: asm.alignstack, dialect: asm.dialect, @@ -1180,7 +1179,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let from_err_expr = self.wrap_in_try_constructor(sym::from_error, unstable_span, from_expr, try_span); let thin_attrs = ThinVec::from(attrs); - let catch_scope = self.catch_scopes.last().map(|x| *x); + let catch_scope = self.catch_scopes.last().copied(); let ret_expr = if let Some(catch_node) = catch_scope { let target_id = Ok(self.lower_node_id(catch_node)); self.arena.alloc(self.expr( diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 73a25620b5a..94ae2a0973a 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -3,18 +3,19 @@ use super::{ImplTraitContext, ImplTraitPosition, ImplTraitTypeIdVisitor}; use rustc::arena::Arena; use rustc::bug; +use rustc_ast::ast::*; +use rustc_ast::attr; +use rustc_ast::node_id::NodeMap; +use rustc_ast::ptr::P; +use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_span::source_map::{respan, DesugaringKind}; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use rustc_target::spec::abi; -use syntax::ast::*; -use syntax::attr; -use syntax::node_id::NodeMap; -use syntax::visit::{self, AssocCtxt, Visitor}; use log::debug; use smallvec::{smallvec, SmallVec}; @@ -66,15 +67,7 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> { if let Some(hir_id) = item_hir_id { self.lctx.with_parent_item_lifetime_defs(hir_id, |this| { let this = &mut ItemLowerer { lctx: this }; - if let ItemKind::Impl { constness, ref of_trait, .. } = item.kind { - if let Const::Yes(span) = constness { - this.lctx - .diagnostic() - .struct_span_err(item.span, "const trait impls are not yet implemented") - .span_label(span, "const because of this") - .emit(); - } - + if let ItemKind::Impl { ref of_trait, .. } = item.kind { this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item)); } else { visit::walk_item(this, item); @@ -122,7 +115,7 @@ impl<'hir> LoweringContext<'_, 'hir> { _ => &[], }; let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind { - hir::GenericParamKind::Lifetime { .. } => Some(param.name.modern()), + hir::GenericParamKind::Lifetime { .. } => Some(param.name.normalize_to_macros_2_0()), _ => None, }); self.in_scope_lifetimes.extend(lt_def_names); @@ -181,7 +174,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ids } - ItemKind::Const(ref ty, ..) => { + ItemKind::Const(_, ref ty, ..) => { let mut ids = smallvec![i.id]; if self.sess.features_untracked().impl_trait_in_bindings { let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids }; @@ -227,18 +220,17 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut vis = self.lower_visibility(&i.vis, None); let attrs = self.lower_attrs(&i.attrs); - if let ItemKind::MacroDef(ref def) = i.kind { - if !def.legacy || attr::contains_name(&i.attrs, sym::macro_export) { - let body = self.lower_token_stream(def.body.inner_tokens()); + if let ItemKind::MacroDef(MacroDef { ref body, macro_rules }) = i.kind { + if !macro_rules || attr::contains_name(&i.attrs, sym::macro_export) { let hir_id = self.lower_node_id(i.id); + let body = P(self.lower_mac_args(body)); self.exported_macros.push(hir::MacroDef { - name: ident.name, + ident, vis, attrs, hir_id, span: i.span, - body, - legacy: def.legacy, + ast: MacroDef { body, macro_rules }, }); } else { self.non_exported_macro_attrs.extend(attrs.iter().cloned()); @@ -269,29 +261,15 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs) } ItemKind::Static(ref t, m, ref e) => { - let ty = self.lower_ty( - t, - if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy(None) - } else { - ImplTraitContext::Disallowed(ImplTraitPosition::Binding) - }, - ); - hir::ItemKind::Static(ty, m, self.lower_const_body(span, Some(e))) + let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); + hir::ItemKind::Static(ty, m, body_id) } - ItemKind::Const(ref t, ref e) => { - let ty = self.lower_ty( - t, - if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy(None) - } else { - ImplTraitContext::Disallowed(ImplTraitPosition::Binding) - }, - ); - hir::ItemKind::Const(ty, self.lower_const_body(span, Some(e))) + ItemKind::Const(_, ref t, ref e) => { + let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); + hir::ItemKind::Const(ty, body_id) } - ItemKind::Fn(FnSig { ref decl, header }, ref generics, ref body) => { - let fn_def_id = self.resolver.definitions().local_def_id(id); + ItemKind::Fn(_, FnSig { ref decl, header }, ref generics, ref body) => { + let fn_def_id = self.resolver.definitions().local_def_id(id).expect_local(); self.with_new_scopes(|this| { this.current_item = Some(ident.span); @@ -309,7 +287,12 @@ impl<'hir> LoweringContext<'_, 'hir> { AnonymousLifetimeMode::PassThrough, |this, idty| { let ret_id = asyncness.opt_return_id(); - this.lower_fn_decl(&decl, Some((fn_def_id, idty)), true, ret_id) + this.lower_fn_decl( + &decl, + Some((fn_def_id.to_def_id(), idty)), + true, + ret_id, + ) }, ); let sig = hir::FnSig { decl, header: this.lower_fn_header(header) }; @@ -319,22 +302,28 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemKind::ForeignMod(self.lower_foreign_mod(nm)), ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)), - ItemKind::TyAlias(ref ty, ref generics) => match ty.kind.opaque_top_hack() { + ItemKind::TyAlias(_, ref gen, _, Some(ref ty)) => match ty.kind.opaque_top_hack() { None => { let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); - let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); + let generics = self.lower_generics(gen, ImplTraitContext::disallowed()); hir::ItemKind::TyAlias(ty, generics) } Some(bounds) => { + let ctx = || ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc); let ty = hir::OpaqueTy { - generics: self.lower_generics(generics, ImplTraitContext::OpaqueTy(None)), - bounds: self.lower_param_bounds(bounds, ImplTraitContext::OpaqueTy(None)), + generics: self.lower_generics(gen, ctx()), + bounds: self.lower_param_bounds(bounds, ctx()), impl_trait_fn: None, origin: hir::OpaqueTyOrigin::TypeAlias, }; hir::ItemKind::OpaqueTy(ty) } }, + ItemKind::TyAlias(_, ref generics, _, None) => { + let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err)); + let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); + hir::ItemKind::TyAlias(ty, generics) + } ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum( hir::EnumDef { variants: self.arena.alloc_from_iter( @@ -367,7 +356,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self_ty: ref ty, items: ref impl_items, } => { - let def_id = self.resolver.definitions().local_def_id(id); + let def_id = self.resolver.definitions().local_def_id(id).expect_local(); // Lower the "impl header" first. This ordering is important // for in-band lifetimes! Consider `'a` here: @@ -442,7 +431,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_generics(generics, ImplTraitContext::disallowed()), self.lower_param_bounds(bounds, ImplTraitContext::disallowed()), ), - ItemKind::MacroDef(..) | ItemKind::Mac(..) => { + ItemKind::MacroDef(..) | ItemKind::MacCall(..) => { bug!("`TyMac` should have been expanded by now") } } @@ -451,6 +440,21 @@ impl<'hir> LoweringContext<'_, 'hir> { // not cause an assertion failure inside the `lower_defaultness` function. } + fn lower_const_item( + &mut self, + ty: &Ty, + span: Span, + body: Option<&Expr>, + ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { + let itctx = if self.sess.features_untracked().impl_trait_in_bindings { + ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc) + } else { + ImplTraitContext::Disallowed(ImplTraitPosition::Binding) + }; + let ty = self.lower_ty(ty, itctx); + (ty, self.lower_const_body(span, body)) + } + fn lower_use_tree( &mut self, tree: &UseTree, @@ -649,13 +653,13 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem<'hir> { - let def_id = self.resolver.definitions().local_def_id(i.id); + let def_id = self.resolver.definitions().local_def_id(i.id).expect_local(); hir::ForeignItem { hir_id: self.lower_node_id(i.id), ident: i.ident, attrs: self.lower_attrs(&i.attrs), kind: match i.kind { - ForeignItemKind::Fn(ref sig, ref generics, _) => { + ForeignItemKind::Fn(_, ref sig, ref generics, _) => { let fdec = &sig.decl; let (generics, (fn_dec, fn_args)) = self.add_in_band_defs( generics, @@ -672,12 +676,12 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ForeignItemKind::Fn(fn_dec, fn_args, generics) } - ForeignItemKind::Static(ref t, m) => { + ForeignItemKind::Static(ref t, m, _) => { let ty = self.lower_ty(t, ImplTraitContext::disallowed()); hir::ForeignItemKind::Static(ty, m) } - ForeignItemKind::Ty => hir::ForeignItemKind::Type, - ForeignItemKind::Macro(_) => panic!("macro shouldn't exist here"), + ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, + ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"), }, vis: self.lower_visibility(&i.vis, None), span: i.span, @@ -750,35 +754,29 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_trait_item(&mut self, i: &AssocItem) -> hir::TraitItem<'hir> { - let trait_item_def_id = self.resolver.definitions().local_def_id(i.id); + let trait_item_def_id = self.resolver.definitions().local_def_id(i.id).expect_local(); let (generics, kind) = match i.kind { - AssocItemKind::Const(ref ty, ref default) => { - let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed()); + AssocItemKind::Const(_, ref ty, ref default) => { let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); - ( - generics, - hir::TraitItemKind::Const( - ty, - default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))), - ), - ) + let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))); + (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body)) } - AssocItemKind::Fn(ref sig, None) => { + AssocItemKind::Fn(_, ref sig, ref generics, None) => { let names = self.lower_fn_params_to_names(&sig.decl); let (generics, sig) = - self.lower_method_sig(&i.generics, sig, trait_item_def_id, false, None); - (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Required(names))) + self.lower_method_sig(generics, sig, trait_item_def_id, false, None); + (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names))) } - AssocItemKind::Fn(ref sig, Some(ref body)) => { + AssocItemKind::Fn(_, ref sig, ref generics, Some(ref body)) => { let body_id = self.lower_fn_body_block(i.span, &sig.decl, Some(body)); let (generics, sig) = - self.lower_method_sig(&i.generics, sig, trait_item_def_id, false, None); - (generics, hir::TraitItemKind::Method(sig, hir::TraitMethod::Provided(body_id))) + self.lower_method_sig(generics, sig, trait_item_def_id, false, None); + (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id))) } - AssocItemKind::TyAlias(ref bounds, ref default) => { + AssocItemKind::TyAlias(_, ref generics, ref bounds, ref default) => { let ty = default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed())); - let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed()); + let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); let kind = hir::TraitItemKind::Type( self.lower_param_bounds(bounds, ImplTraitContext::disallowed()), ty, @@ -786,7 +784,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (generics, kind) } - AssocItemKind::Macro(..) => bug!("macro item shouldn't exist at this point"), + AssocItemKind::MacCall(..) => bug!("macro item shouldn't exist at this point"), }; hir::TraitItem { @@ -800,21 +798,19 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef { - let (kind, has_default) = match i.kind { - AssocItemKind::Const(_, ref default) => (hir::AssocItemKind::Const, default.is_some()), - AssocItemKind::TyAlias(_, ref default) => (hir::AssocItemKind::Type, default.is_some()), - AssocItemKind::Fn(ref sig, ref default) => { + let (kind, has_default) = match &i.kind { + AssocItemKind::Const(_, _, default) => (hir::AssocItemKind::Const, default.is_some()), + AssocItemKind::TyAlias(_, _, _, default) => { + (hir::AssocItemKind::Type, default.is_some()) + } + AssocItemKind::Fn(_, sig, _, default) => { (hir::AssocItemKind::Method { has_self: sig.decl.has_self() }, default.is_some()) } - AssocItemKind::Macro(..) => unimplemented!(), + AssocItemKind::MacCall(..) => unimplemented!(), }; - hir::TraitItemRef { - id: hir::TraitItemId { hir_id: self.lower_node_id(i.id) }, - ident: i.ident, - span: i.span, - defaultness: self.lower_defaultness(Defaultness::Default, has_default), - kind, - } + let id = hir::TraitItemId { hir_id: self.lower_node_id(i.id) }; + let defaultness = hir::Defaultness::Default { has_value: has_default }; + hir::TraitItemRef { id, ident: i.ident, span: i.span, defaultness, kind } } /// Construct `ExprKind::Err` for the given `span`. @@ -823,35 +819,34 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_impl_item(&mut self, i: &AssocItem) -> hir::ImplItem<'hir> { - let impl_item_def_id = self.resolver.definitions().local_def_id(i.id); + let impl_item_def_id = self.resolver.definitions().local_def_id(i.id).expect_local(); - let (generics, kind) = match i.kind { - AssocItemKind::Const(ref ty, ref expr) => { - let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed()); + let (generics, kind) = match &i.kind { + AssocItemKind::Const(_, ty, expr) => { let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); ( - generics, + hir::Generics::empty(), hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())), ) } - AssocItemKind::Fn(ref sig, ref body) => { + AssocItemKind::Fn(_, sig, generics, body) => { self.current_item = Some(i.span); let asyncness = sig.header.asyncness; let body_id = self.lower_maybe_async_body(i.span, &sig.decl, asyncness, body.as_deref()); let impl_trait_return_allow = !self.is_in_trait_impl; let (generics, sig) = self.lower_method_sig( - &i.generics, + generics, sig, impl_item_def_id, impl_trait_return_allow, asyncness.opt_return_id(), ); - (generics, hir::ImplItemKind::Method(sig, body_id)) + (generics, hir::ImplItemKind::Fn(sig, body_id)) } - AssocItemKind::TyAlias(_, ref ty) => { - let generics = self.lower_generics(&i.generics, ImplTraitContext::disallowed()); + AssocItemKind::TyAlias(_, generics, _, ty) => { + let generics = self.lower_generics(generics, ImplTraitContext::disallowed()); let kind = match ty { None => { let ty = self.arena.alloc(self.ty(i.span, hir::TyKind::Err)); @@ -870,7 +865,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }; (generics, kind) } - AssocItemKind::Macro(..) => bug!("`TyMac` should have been expanded by now"), + AssocItemKind::MacCall(..) => bug!("`TyMac` should have been expanded by now"), }; hir::ImplItem { @@ -879,7 +874,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: self.lower_attrs(&i.attrs), generics, vis: self.lower_visibility(&i.vis, None), - defaultness: self.lower_defaultness(i.defaultness, true /* [1] */), + defaultness: self.lower_defaultness(i.kind.defaultness(), true /* [1] */), kind, span: i.span, } @@ -893,19 +888,19 @@ impl<'hir> LoweringContext<'_, 'hir> { ident: i.ident, span: i.span, vis: self.lower_visibility(&i.vis, Some(i.id)), - defaultness: self.lower_defaultness(i.defaultness, true /* [1] */), + defaultness: self.lower_defaultness(i.kind.defaultness(), true /* [1] */), kind: match &i.kind { AssocItemKind::Const(..) => hir::AssocItemKind::Const, - AssocItemKind::TyAlias(_, ty) => { + AssocItemKind::TyAlias(.., ty) => { match ty.as_deref().and_then(|ty| ty.kind.opaque_top_hack()) { None => hir::AssocItemKind::Type, Some(_) => hir::AssocItemKind::OpaqueTy, } } - AssocItemKind::Fn(sig, _) => { + AssocItemKind::Fn(_, sig, ..) => { hir::AssocItemKind::Method { has_self: sig.decl.has_self() } } - AssocItemKind::Macro(..) => unimplemented!(), + AssocItemKind::MacCall(..) => unimplemented!(), }, } @@ -946,7 +941,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_defaultness(&self, d: Defaultness, has_value: bool) -> hir::Defaultness { match d { - Defaultness::Default => hir::Defaultness::Default { has_value: has_value }, + Defaultness::Default(_) => hir::Defaultness::Default { has_value }, Defaultness::Final => { assert!(has_value); hir::Defaultness::Final @@ -1221,7 +1216,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, generics: &Generics, sig: &FnSig, - fn_def_id: DefId, + fn_def_id: LocalDefId, impl_trait_return_allow: bool, is_async: Option, ) -> (hir::Generics<'hir>, hir::FnSig<'hir>) { @@ -1233,7 +1228,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |this, idty| { this.lower_fn_decl( &sig.decl, - Some((fn_def_id, idty)), + Some((fn_def_id.to_def_id(), idty)), impl_trait_return_allow, is_async, ) diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 618b1e7964b..dcedcd51f50 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -37,8 +37,15 @@ use rustc::arena::Arena; use rustc::dep_graph::DepGraph; use rustc::hir::map::definitions::{DefKey, DefPathData, Definitions}; -use rustc::hir::map::Map; use rustc::{bug, span_bug}; +use rustc_ast::ast; +use rustc_ast::ast::*; +use rustc_ast::attr; +use rustc_ast::node_id::NodeMap; +use rustc_ast::token::{self, Nonterminal, Token}; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::visit::{self, AssocCtxt, Visitor}; +use rustc_ast::walk_list; use rustc_ast_pretty::pprust; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; @@ -46,7 +53,7 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res}; -use rustc_hir::def_id::{DefId, DefIdMap, DefIndex, CRATE_DEF_INDEX}; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::intravisit; use rustc_hir::{ConstArg, GenericArg, ParamName}; use rustc_index::vec::IndexVec; @@ -58,14 +65,6 @@ use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{respan, DesugaringKind, ExpnData, ExpnKind}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use syntax::ast; -use syntax::ast::*; -use syntax::attr; -use syntax::node_id::NodeMap; -use syntax::token::{self, Nonterminal, Token}; -use syntax::tokenstream::{TokenStream, TokenTree}; -use syntax::visit::{self, AssocCtxt, Visitor}; -use syntax::walk_list; use log::{debug, trace}; use smallvec::{smallvec, SmallVec}; @@ -153,7 +152,7 @@ struct LoweringContext<'a, 'hir: 'a> { /// against this list to see if it is already in-scope, or if a definition /// needs to be created for it. /// - /// We always store a `modern()` version of the param-name in this + /// We always store a `normalize_to_macros_2_0()` version of the param-name in this /// vector. in_scope_lifetimes: Vec, @@ -161,7 +160,7 @@ struct LoweringContext<'a, 'hir: 'a> { type_def_lifetime_params: DefIdMap, - current_hir_id_owner: Vec<(DefIndex, u32)>, + current_hir_id_owner: Vec<(LocalDefId, u32)>, item_local_id_counters: NodeMap, node_id_to_hir_id: IndexVec, @@ -222,7 +221,7 @@ enum ImplTraitContext<'b, 'a> { /// We optionally store a `DefId` for the parent item here so we can look up necessary /// information later. It is `None` when no information about the context should be stored /// (e.g., for consts and statics). - OpaqueTy(Option /* fn def-ID */), + OpaqueTy(Option /* fn def-ID */, hir::OpaqueTyOrigin), /// `impl Trait` is not accepted in this position. Disallowed(ImplTraitPosition), @@ -248,7 +247,7 @@ impl<'a> ImplTraitContext<'_, 'a> { use self::ImplTraitContext::*; match self { Universal(params) => Universal(params), - OpaqueTy(fn_def_id) => OpaqueTy(*fn_def_id), + OpaqueTy(fn_def_id, origin) => OpaqueTy(*fn_def_id, *origin), Disallowed(pos) => Disallowed(*pos), } } @@ -291,7 +290,7 @@ pub fn lower_crate<'a, 'hir>( anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough, type_def_lifetime_params: Default::default(), current_module: hir::CRATE_HIR_ID, - current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)], + current_hir_id_owner: vec![(LocalDefId { local_def_index: CRATE_DEF_INDEX }, 0)], item_local_id_counters: Default::default(), node_id_to_hir_id: IndexVec::new(), generator_kind: None, @@ -408,7 +407,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } impl MiscCollector<'_, '_, '_> { - fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree, owner: DefIndex) { + fn allocate_use_tree_hir_id_counters(&mut self, tree: &UseTree, owner: LocalDefId) { match tree.kind { UseTreeKind::Simple(_, id1, id2) => { for &id in &[id1, id2] { @@ -462,9 +461,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ItemKind::Struct(_, ref generics) | ItemKind::Union(_, ref generics) | ItemKind::Enum(_, ref generics) - | ItemKind::TyAlias(_, ref generics) + | ItemKind::TyAlias(_, ref generics, ..) | ItemKind::Trait(_, _, ref generics, ..) => { - let def_id = self.lctx.resolver.definitions().local_def_id(item.id); + let def_id = + self.lctx.resolver.definitions().local_def_id(item.id).expect_local(); let count = generics .params .iter() @@ -473,7 +473,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => false, }) .count(); - self.lctx.type_def_lifetime_params.insert(def_id, count); + self.lctx.type_def_lifetime_params.insert(def_id.to_def_id(), count); } ItemKind::Use(ref use_tree) => { self.allocate_use_tree_hir_id_counters(use_tree, hir_id.owner); @@ -490,7 +490,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lctx.allocate_hir_id_counter(item.id); let owner = match (&item.kind, ctxt) { // Ignore patterns in trait methods without bodies. - (AssocItemKind::Fn(_, None), AssocCtxt::Trait) => None, + (AssocItemKind::Fn(_, _, _, None), AssocCtxt::Trait) => None, _ => Some(item.id), }; self.with_hir_id_owner(owner, |this| visit::walk_assoc_item(this, item, ctxt)); @@ -530,13 +530,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let module = self.lower_mod(&c.module); let attrs = self.lower_attrs(&c.attrs); let body_ids = body_ids(&self.bodies); + let proc_macros = c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id]).collect(); self.resolver.definitions().init_node_id_to_hir_id_mapping(self.node_id_to_hir_id); hir::Crate { - module, - attrs, - span: c.span, + item: hir::CrateItem { module, attrs, span: c.span }, exported_macros: self.arena.alloc_from_iter(self.exported_macros), non_exported_macro_attrs: self.arena.alloc_from_iter(self.non_exported_macro_attrs), items: self.items, @@ -546,6 +545,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { body_ids, trait_impls: self.trait_impls, modules: self.modules, + proc_macros, } } @@ -599,12 +599,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .item_local_id_counters .insert(owner, HIR_ID_COUNTER_LOCKED) .unwrap_or_else(|| panic!("no `item_local_id_counters` entry for {:?}", owner)); - let def_index = self.resolver.definitions().opt_def_index(owner).unwrap(); - self.current_hir_id_owner.push((def_index, counter)); + let def_id = self.resolver.definitions().local_def_id(owner).expect_local(); + self.current_hir_id_owner.push((def_id, counter)); let ret = f(self); - let (new_def_index, new_counter) = self.current_hir_id_owner.pop().unwrap(); + let (new_def_id, new_counter) = self.current_hir_id_owner.pop().unwrap(); - debug_assert!(def_index == new_def_index); + debug_assert!(def_id == new_def_id); debug_assert!(new_counter >= counter); let prev = self.item_local_id_counters.insert(owner, new_counter).unwrap(); @@ -620,11 +620,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// properly. Calling the method twice with the same `NodeId` is fine though. fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId { self.lower_node_id_generic(ast_node_id, |this| { - let &mut (def_index, ref mut local_id_counter) = + let &mut (owner, ref mut local_id_counter) = this.current_hir_id_owner.last_mut().unwrap(); let local_id = *local_id_counter; *local_id_counter += 1; - hir::HirId { owner: def_index, local_id: hir::ItemLocalId::from_u32(local_id) } + hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) } }) } @@ -642,12 +642,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug_assert!(local_id != HIR_ID_COUNTER_LOCKED); *local_id_counter += 1; - let def_index = this.resolver.definitions().opt_def_index(owner).expect( + let owner = this.resolver.definitions().opt_local_def_id(owner).expect( "you forgot to call `create_def_with_parent` or are lowering node-IDs \ - that do not belong to the current owner", + that do not belong to the current owner", ); - hir::HirId { owner: def_index, local_id: hir::ItemLocalId::from_u32(local_id) } + hir::HirId { owner, local_id: hir::ItemLocalId::from_u32(local_id) } }) } @@ -725,7 +725,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// parameter while `f` is running (and restored afterwards). fn collect_in_band_defs( &mut self, - parent_id: DefId, + parent_def_id: LocalDefId, anonymous_lifetime_mode: AnonymousLifetimeMode, f: impl FnOnce(&mut Self) -> (Vec>, T), ) -> (Vec>, T) { @@ -745,7 +745,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let params = lifetimes_to_define .into_iter() - .map(|(span, hir_name)| self.lifetime_to_generic_param(span, hir_name, parent_id.index)) + .map(|(span, hir_name)| self.lifetime_to_generic_param(span, hir_name, parent_def_id)) .chain(in_band_ty_params.into_iter()) .collect(); @@ -757,7 +757,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, span: Span, hir_name: ParamName, - parent_index: DefIndex, + parent_def_id: LocalDefId, ) -> hir::GenericParam<'hir> { let node_id = self.resolver.next_node_id(); @@ -772,7 +772,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Add a definition for the in-band lifetime def. self.resolver.definitions().create_def_with_parent( - parent_index, + parent_def_id, node_id, DefPathData::LifetimeNs(str_name), ExpnId::root(), @@ -803,14 +803,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { return; } - if self.in_scope_lifetimes.contains(&ParamName::Plain(ident.modern())) { + if self.in_scope_lifetimes.contains(&ParamName::Plain(ident.normalize_to_macros_2_0())) { return; } let hir_name = ParamName::Plain(ident); - if self.lifetimes_to_define.iter().any(|(_, lt_name)| lt_name.modern() == hir_name.modern()) - { + if self.lifetimes_to_define.iter().any(|(_, lt_name)| { + lt_name.normalize_to_macros_2_0() == hir_name.normalize_to_macros_2_0() + }) { return; } @@ -838,7 +839,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> T { let old_len = self.in_scope_lifetimes.len(); let lt_def_names = params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some(ParamName::Plain(param.ident.modern())), + GenericParamKind::Lifetime { .. } => { + Some(ParamName::Plain(param.ident.normalize_to_macros_2_0())) + } _ => None, }); self.in_scope_lifetimes.extend(lt_def_names); @@ -858,13 +861,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn add_in_band_defs( &mut self, generics: &Generics, - parent_id: DefId, + parent_def_id: LocalDefId, anonymous_lifetime_mode: AnonymousLifetimeMode, f: impl FnOnce(&mut Self, &mut Vec>) -> T, ) -> (hir::Generics<'hir>, T) { let (in_band_defs, (mut lowered_generics, res)) = self.with_in_scope_lifetime_defs(&generics.params, |this| { - this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| { + this.collect_in_band_defs(parent_def_id, anonymous_lifetime_mode, |this| { let mut params = Vec::new(); // Note: it is necessary to lower generics *before* calling `f`. // When lowering `async fn`, there's a final step when lowering @@ -1010,7 +1013,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so desugar to // // fn foo() -> impl Iterator - ImplTraitContext::OpaqueTy(_) => (true, itctx), + ImplTraitContext::OpaqueTy(..) => (true, itctx), // We are in the argument position, but within a dyn type: // @@ -1019,7 +1022,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so desugar to // // fn foo(x: dyn Iterator) - ImplTraitContext::Universal(_) if self.is_in_dyn_type => (true, itctx), + ImplTraitContext::Universal(..) if self.is_in_dyn_type => (true, itctx), // In `type Foo = dyn Iterator` we desugar to // `type Foo = dyn Iterator` but we have to override the @@ -1028,7 +1031,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // FIXME: this is only needed until `impl Trait` is allowed in type aliases. ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => { - (true, ImplTraitContext::OpaqueTy(None)) + (true, ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)) } // We are in the parameter position, but not within a dyn type: @@ -1046,9 +1049,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // constructing the HIR for `impl bounds...` and then lowering that. let impl_trait_node_id = self.resolver.next_node_id(); - let parent_def_index = self.current_hir_id_owner.last().unwrap().0; + let parent_def_id = self.current_hir_id_owner.last().unwrap().0; self.resolver.definitions().create_def_with_parent( - parent_def_index, + parent_def_id, impl_trait_node_id, DefPathData::ImplTrait, ExpnId::root(), @@ -1094,7 +1097,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)), ast::GenericArg::Type(ty) => { - // We parse const arguments as path types as we cannot distiguish them durring + // We parse const arguments as path types as we cannot distinguish them during // parsing. We try to resolve that ambiguity by attempting resolution in both the // type and value namespaces. If we resolved the path in the value namespace, we // transform it into a generic const argument. @@ -1109,12 +1112,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Construct a AnonConst where the expr is the "ty"'s path. - let parent_def_index = self.current_hir_id_owner.last().unwrap().0; + let parent_def_id = self.current_hir_id_owner.last().unwrap().0; let node_id = self.resolver.next_node_id(); // Add a definition for the in-band const def. self.resolver.definitions().create_def_with_parent( - parent_def_index, + parent_def_id, node_id, DefPathData::AnonConst, ExpnId::root(), @@ -1269,15 +1272,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::ImplTrait(def_node_id, ref bounds) => { let span = t.span; match itctx { - ImplTraitContext::OpaqueTy(fn_def_id) => { - self.lower_opaque_impl_trait(span, fn_def_id, def_node_id, |this| { + ImplTraitContext::OpaqueTy(fn_def_id, origin) => { + self.lower_opaque_impl_trait(span, fn_def_id, origin, def_node_id, |this| { this.lower_param_bounds(bounds, itctx) }) } ImplTraitContext::Universal(in_band_ty_params) => { // Add a definition for the in-band `Param`. - let def_index = - self.resolver.definitions().opt_def_index(def_node_id).unwrap(); + let def_id = + self.resolver.definitions().local_def_id(def_node_id).expect_local(); let hir_bounds = self.lower_param_bounds( bounds, @@ -1302,7 +1305,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { None, self.arena.alloc(hir::Path { span, - res: Res::Def(DefKind::TyParam, DefId::local(def_index)), + res: Res::Def(DefKind::TyParam, def_id.to_def_id()), segments: arena_vec![self; hir::PathSegment::from_ident(ident)], }), )) @@ -1332,7 +1335,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } } - TyKind::Mac(_) => bug!("`TyKind::Mac` should have been expanded by now"), + TyKind::MacCall(_) => bug!("`TyKind::MacCall` should have been expanded by now"), TyKind::CVarArgs => { self.sess.delay_span_bug( t.span, @@ -1349,6 +1352,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, span: Span, fn_def_id: Option, + origin: hir::OpaqueTyOrigin, opaque_ty_node_id: NodeId, lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>, ) -> hir::TyKind<'hir> { @@ -1364,18 +1368,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // frequently opened issues show. let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None); - let opaque_ty_def_index = - self.resolver.definitions().opt_def_index(opaque_ty_node_id).unwrap(); + let opaque_ty_def_id = + self.resolver.definitions().local_def_id(opaque_ty_node_id).expect_local(); self.allocate_hir_id_counter(opaque_ty_node_id); let hir_bounds = self.with_hir_id_owner(opaque_ty_node_id, lower_bounds); - let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds( - opaque_ty_node_id, - opaque_ty_def_index, - &hir_bounds, - ); + let (lifetimes, lifetime_defs) = + self.lifetimes_from_impl_trait_bounds(opaque_ty_node_id, opaque_ty_def_id, &hir_bounds); debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes,); @@ -1390,10 +1391,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }, bounds: hir_bounds, impl_trait_fn: fn_def_id, - origin: hir::OpaqueTyOrigin::FnReturn, + origin, }; - trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_index); + trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_id); let opaque_ty_id = lctx.generate_opaque_type(opaque_ty_node_id, opaque_ty_item, span, opaque_ty_span); @@ -1434,14 +1435,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lifetimes_from_impl_trait_bounds( &mut self, opaque_ty_id: NodeId, - parent_index: DefIndex, + parent_def_id: LocalDefId, bounds: hir::GenericBounds<'hir>, ) -> (&'hir [hir::GenericArg<'hir>], &'hir [hir::GenericParam<'hir>]) { debug!( "lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \ - parent_index={:?}, \ + parent_def_id={:?}, \ bounds={:#?})", - opaque_ty_id, parent_index, bounds, + opaque_ty_id, parent_def_id, bounds, ); // This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that @@ -1449,7 +1450,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`. struct ImplTraitLifetimeCollector<'r, 'a, 'hir> { context: &'r mut LoweringContext<'a, 'hir>, - parent: DefIndex, + parent: LocalDefId, opaque_ty_id: NodeId, collect_elided_lifetimes: bool, currently_bound_lifetimes: Vec, @@ -1459,9 +1460,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } impl<'r, 'a, 'v, 'hir> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r, 'a, 'hir> { - type Map = Map<'v>; + type Map = intravisit::ErasedMap<'v>; - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { intravisit::NestedVisitorMap::None } @@ -1587,7 +1588,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut lifetime_collector = ImplTraitLifetimeCollector { context: self, - parent: parent_index, + parent: parent_def_id, opaque_ty_id, collect_elided_lifetimes: true, currently_bound_lifetimes: Vec::new(), @@ -1617,12 +1618,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { visitor.visit_ty(ty); } } - let parent_def_id = DefId::local(self.current_hir_id_owner.last().unwrap().0); + let parent_def_id = self.current_hir_id_owner.last().unwrap().0; let ty = l.ty.as_ref().map(|t| { self.lower_ty( t, if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy(Some(parent_def_id)) + ImplTraitContext::OpaqueTy( + Some(parent_def_id.to_def_id()), + hir::OpaqueTyOrigin::Misc, + ) } else { ImplTraitContext::Disallowed(ImplTraitPosition::Binding) }, @@ -1722,15 +1726,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } else { match decl.output { - FunctionRetTy::Ty(ref ty) => match in_band_ty_params { - Some((def_id, _)) if impl_trait_return_allow => hir::FunctionRetTy::Return( - self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(def_id))), - ), - _ => hir::FunctionRetTy::Return( - self.lower_ty(ty, ImplTraitContext::disallowed()), - ), - }, - FunctionRetTy::Default(span) => hir::FunctionRetTy::DefaultReturn(span), + FnRetTy::Ty(ref ty) => { + let context = match in_band_ty_params { + Some((def_id, _)) if impl_trait_return_allow => { + ImplTraitContext::OpaqueTy(Some(def_id), hir::OpaqueTyOrigin::FnReturn) + } + _ => ImplTraitContext::disallowed(), + }; + hir::FnRetTy::Return(self.lower_ty(ty, context)) + } + FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(span), } }; @@ -1777,10 +1782,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `elided_lt_replacement`: replacement for elided lifetimes in the return type fn lower_async_fn_ret_ty( &mut self, - output: &FunctionRetTy, + output: &FnRetTy, fn_def_id: DefId, opaque_ty_node_id: NodeId, - ) -> hir::FunctionRetTy<'hir> { + ) -> hir::FnRetTy<'hir> { debug!( "lower_async_fn_ret_ty(\ output={:?}, \ @@ -1793,8 +1798,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None); - let opaque_ty_def_index = - self.resolver.definitions().opt_def_index(opaque_ty_node_id).unwrap(); + let opaque_ty_def_id = + self.resolver.definitions().local_def_id(opaque_ty_node_id).expect_local(); self.allocate_hir_id_counter(opaque_ty_node_id); @@ -1882,7 +1887,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let generic_params = this.arena.alloc_from_iter(lifetime_params.iter().map(|(span, hir_name)| { - this.lifetime_to_generic_param(*span, *hir_name, opaque_ty_def_index) + this.lifetime_to_generic_param(*span, *hir_name, opaque_ty_def_id) })); let opaque_ty_item = hir::OpaqueTy { @@ -1896,7 +1901,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { origin: hir::OpaqueTyOrigin::AsyncFn, }; - trace!("exist ty from async fn def index: {:#?}", opaque_ty_def_index); + trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id); let opaque_ty_id = this.generate_opaque_type(opaque_ty_node_id, opaque_ty_item, span, opaque_ty_span); @@ -1945,20 +1950,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // only the lifetime parameters that we must supply. let opaque_ty_ref = hir::TyKind::Def(hir::ItemId { id: opaque_ty_id }, generic_args); let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref); - hir::FunctionRetTy::Return(self.arena.alloc(opaque_ty)) + hir::FnRetTy::Return(self.arena.alloc(opaque_ty)) } /// Transforms `-> T` into `Future` fn lower_async_fn_output_type_to_future_bound( &mut self, - output: &FunctionRetTy, + output: &FnRetTy, fn_def_id: DefId, span: Span, ) -> hir::GenericBound<'hir> { // Compute the `T` in `Future` from the return type. let output_ty = match output { - FunctionRetTy::Ty(ty) => self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(fn_def_id))), - FunctionRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), + FnRetTy::Ty(ty) => { + // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the + // `impl Future` opaque type that `async fn` implicitly + // generates. + let context = + ImplTraitContext::OpaqueTy(Some(fn_def_id), hir::OpaqueTyOrigin::FnReturn); + self.lower_ty(ty, context) + } + FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), }; // "" @@ -2102,9 +2114,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let kind = hir::GenericParamKind::Type { - default: default - .as_ref() - .map(|x| self.lower_ty(x, ImplTraitContext::OpaqueTy(None))), + default: default.as_ref().map(|x| { + self.lower_ty( + x, + ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc), + ) + }), synthetic: param .attrs .iter() @@ -2267,7 +2282,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } StmtKind::Expr(ref e) => hir::StmtKind::Expr(self.lower_expr(e)), StmtKind::Semi(ref e) => hir::StmtKind::Semi(self.lower_expr(e)), - StmtKind::Mac(..) => panic!("shouldn't exist here"), + StmtKind::Empty => return smallvec![], + StmtKind::MacCall(..) => panic!("shouldn't exist here"), }; smallvec![hir::Stmt { hir_id: self.lower_node_id(s.id), kind, span: s.span }] } diff --git a/src/librustc_ast_lowering/pat.rs b/src/librustc_ast_lowering/pat.rs index 4c3c4ddac78..8ba6576f692 100644 --- a/src/librustc_ast_lowering/pat.rs +++ b/src/librustc_ast_lowering/pat.rs @@ -1,10 +1,10 @@ use super::{ImplTraitContext, LoweringContext, ParamMode}; +use rustc_ast::ast::*; +use rustc_ast::ptr::P; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_span::{source_map::Spanned, Span}; -use syntax::ast::*; -use syntax::ptr::P; impl<'a, 'hir> LoweringContext<'a, 'hir> { crate fn lower_pat(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { @@ -75,7 +75,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.ban_illegal_rest_pat(p.span) } PatKind::Paren(ref inner) => return self.lower_pat(inner), - PatKind::Mac(_) => panic!("Shouldn't exist here"), + PatKind::MacCall(_) => panic!("Shouldn't exist here"), }; self.pat_with_node_id_of(p, node) @@ -128,6 +128,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut slice = None; let mut prev_rest_span = None; + // Lowers `$bm $ident @ ..` to `$bm $ident @ _`. + let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| { + let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub)); + let node = this.lower_pat_ident(pat, bm, ident, lower_sub); + this.pat_with_node_id_of(pat, node) + }; + let mut iter = pats.iter(); // Lower all the patterns until the first occurrence of a sub-slice pattern. for pat in iter.by_ref() { @@ -142,9 +149,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Record, lower it to `$binding_mode $ident @ _`, and stop here. PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => { prev_rest_span = Some(sub.span); - let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub)); - let node = self.lower_pat_ident(pat, bm, ident, lower_sub); - slice = Some(self.pat_with_node_id_of(pat, node)); + slice = Some(lower_rest_sub(self, pat, bm, ident, sub)); break; } // It was not a subslice pattern so lower it normally. @@ -157,9 +162,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // There was a previous subslice pattern; make sure we don't allow more. let rest_span = match pat.kind { PatKind::Rest => Some(pat.span), - PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => { - // The `HirValidator` is merciless; add a `_` pattern to avoid ICEs. - after.push(self.pat_wild_with_node_id_of(pat)); + PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => { + // #69103: Lower into `binding @ _` as above to avoid ICEs. + after.push(lower_rest_sub(self, pat, bm, ident, sub)); Some(sub.span) } _ => None, diff --git a/src/librustc_ast_lowering/path.rs b/src/librustc_ast_lowering/path.rs index e5f7df6dbf9..b5b0a3089ce 100644 --- a/src/librustc_ast_lowering/path.rs +++ b/src/librustc_ast_lowering/path.rs @@ -1,16 +1,16 @@ use super::{AnonymousLifetimeMode, ImplTraitContext, LoweringContext, ParamMode}; use super::{GenericArgsCtor, ParenthesizedGenericArgs}; -use rustc::lint::builtin::ELIDED_LIFETIMES_IN_PATHS; use rustc::span_bug; +use rustc_ast::ast::{self, *}; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; +use rustc_session::lint::builtin::ELIDED_LIFETIMES_IN_PATHS; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::Span; -use syntax::ast::{self, *}; use log::debug; use smallvec::smallvec; @@ -75,7 +75,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ParenthesizedGenericArgs::Ok } // `a::b::Trait(Args)::TraitItem` - Res::Def(DefKind::Method, _) + Res::Def(DefKind::AssocFn, _) | Res::Def(DefKind::AssocConst, _) | Res::Def(DefKind::AssocTy, _) if i + 2 == proj_start => @@ -229,7 +229,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { err.span_label(data.span, "only `Fn` traits may use parentheses"); if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) { // Do not suggest going from `Trait()` to `Trait<>` - if data.inputs.len() > 0 { + if !data.inputs.is_empty() { if let Some(split) = snippet.find('(') { let trait_name = &snippet[0..split]; let args = &snippet[split + 1..snippet.len() - 1]; @@ -397,8 +397,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())), ); let output_ty = match output { - FunctionRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()), - FunctionRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])), + FnRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()), + FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])), }; let args = smallvec![GenericArg::Type(this.ty_tup(span, inputs))]; let binding = this.output_ty_binding(output_ty.span, output_ty); diff --git a/src/librustc_ast_passes/Cargo.toml b/src/librustc_ast_passes/Cargo.toml index 01d2ac449b5..5d096e4965d 100644 --- a/src/librustc_ast_passes/Cargo.toml +++ b/src/librustc_ast_passes/Cargo.toml @@ -18,4 +18,4 @@ rustc_feature = { path = "../librustc_feature" } rustc_parse = { path = "../librustc_parse" } rustc_session = { path = "../librustc_session" } rustc_span = { path = "../librustc_span" } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 2f0495b8b5a..541c681840f 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -6,9 +6,15 @@ // This pass is supposed to perform only simple checks not requiring name resolution // or type checking or some other kind of complex analysis. +use rustc_ast::ast::*; +use rustc_ast::attr; +use rustc_ast::expand::is_proc_macro_attr; +use rustc_ast::ptr::P; +use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; +use rustc_ast::walk_list; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{error_code, struct_span_err, Applicability, FatalError}; +use rustc_errors::{error_code, struct_span_err, Applicability}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY; use rustc_session::lint::LintBuffer; @@ -16,11 +22,9 @@ use rustc_session::Session; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use std::mem; -use syntax::ast::*; -use syntax::attr; -use syntax::expand::is_proc_macro_attr; -use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; -use syntax::walk_list; + +const MORE_EXTERN: &str = + "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html"; /// Is `self` allowed semantically as the first parameter in an `FnDecl`? enum SelfSemantic { @@ -397,9 +401,11 @@ impl<'a> AstValidator<'a> { } fn check_defaultness(&self, span: Span, defaultness: Defaultness) { - if let Defaultness::Default = defaultness { + if let Defaultness::Default(def_span) = defaultness { + let span = self.session.source_map().def_span(span); self.err_handler() .struct_span_err(span, "`default` is only allowed on items in `impl` definitions") + .span_label(def_span, "`default` because of this") .emit(); } } @@ -423,14 +429,62 @@ impl<'a> AstValidator<'a> { } } - fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) { + fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) { let span = match bounds { [] => return, [b0] => b0.span(), [b0, .., bl] => b0.span().to(bl.span()), }; self.err_handler() - .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect") + .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx)) + .emit(); + } + + fn check_foreign_ty_genericless(&self, generics: &Generics) { + let cannot_have = |span, descr, remove_descr| { + self.err_handler() + .struct_span_err( + span, + &format!("`type`s inside `extern` blocks cannot have {}", descr), + ) + .span_suggestion( + span, + &format!("remove the {}", remove_descr), + String::new(), + Applicability::MaybeIncorrect, + ) + .span_label(self.current_extern_span(), "`extern` block begins here") + .note(MORE_EXTERN) + .emit(); + }; + + if !generics.params.is_empty() { + cannot_have(generics.span, "generic parameters", "generic parameters"); + } + + if !generics.where_clause.predicates.is_empty() { + cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause"); + } + } + + fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option) { + let body = match body { + None => return, + Some(body) => body, + }; + self.err_handler() + .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind)) + .span_label(ident.span, "cannot have a body") + .span_label(body, "the invalid body") + .span_label( + self.current_extern_span(), + format!( + "`extern` blocks define existing foreign {0}s and {0}s \ + inside of them cannot have a body", + kind + ), + ) + .note(MORE_EXTERN) .emit(); } @@ -458,7 +512,7 @@ impl<'a> AstValidator<'a> { "`extern` blocks define existing foreign functions and functions \ inside of them cannot have a body", ) - .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html") + .note(MORE_EXTERN) .emit(); } @@ -531,25 +585,75 @@ impl<'a> AstValidator<'a> { } } } -} -enum GenericPosition { - Param, - Arg, + fn check_item_named(&self, ident: Ident, kind: &str) { + if ident.name != kw::Underscore { + return; + } + self.err_handler() + .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind)) + .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind)) + .emit(); + } + + fn deny_generic_params(&self, generics: &Generics, ident_span: Span) { + if !generics.params.is_empty() { + struct_span_err!( + self.session, + generics.span, + E0567, + "auto traits cannot have generic parameters" + ) + .span_label(ident_span, "auto trait cannot have generic parameters") + .span_suggestion( + generics.span, + "remove the parameters", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + } + } + + fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) { + if let [first @ last] | [first, .., last] = &bounds[..] { + let span = first.span().to(last.span()); + struct_span_err!(self.session, span, E0568, "auto traits cannot have super traits") + .span_label(ident_span, "auto trait cannot have super traits") + .span_suggestion( + span, + "remove the super traits", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + } + } + + fn deny_items(&self, trait_items: &[P], ident_span: Span) { + if !trait_items.is_empty() { + let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect(); + struct_span_err!( + self.session, + spans, + E0380, + "auto traits cannot have methods or associated items" + ) + .span_label(ident_span, "auto trait cannot have items") + .emit(); + } + } } -fn validate_generics_order<'a>( +fn validate_generic_param_order<'a>( sess: &Session, handler: &rustc_errors::Handler, generics: impl Iterator, Span, Option)>, - pos: GenericPosition, span: Span, ) { let mut max_param: Option = None; let mut out_of_order = FxHashMap::default(); let mut param_idents = vec![]; - let mut found_type = false; - let mut found_const = false; for (kind, bounds, span, ident) in generics { if let Some(ident) = ident { @@ -563,11 +667,6 @@ fn validate_generics_order<'a>( } Some(_) | None => *max_param = Some(kind), }; - match kind { - ParamKindOrd::Type => found_type = true, - ParamKindOrd::Const => found_const = true, - _ => {} - } } let mut ordered_params = "<".to_string(); @@ -590,42 +689,26 @@ fn validate_generics_order<'a>( } ordered_params += ">"; - let pos_str = match pos { - GenericPosition::Param => "parameter", - GenericPosition::Arg => "argument", - }; - for (param_ord, (max_param, spans)) in &out_of_order { - let mut err = handler.struct_span_err( - spans.clone(), - &format!( - "{} {pos}s must be declared prior to {} {pos}s", - param_ord, - max_param, - pos = pos_str, - ), - ); - if let GenericPosition::Param = pos { - err.span_suggestion( - span, + let mut err = + handler.struct_span_err( + spans.clone(), &format!( - "reorder the {}s: lifetimes, then types{}", - pos_str, - if sess.features_untracked().const_generics { ", then consts" } else { "" }, + "{} parameters must be declared prior to {} parameters", + param_ord, max_param, ), - ordered_params.clone(), - Applicability::MachineApplicable, ); - } + err.span_suggestion( + span, + &format!( + "reorder the parameters: lifetimes, then types{}", + if sess.features_untracked().const_generics { ", then consts" } else { "" }, + ), + ordered_params.clone(), + Applicability::MachineApplicable, + ); err.emit(); } - - // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs - // if we don't. Const parameters and type parameters can currently conflict if they - // are out-of-order. - if !out_of_order.is_empty() && found_type && found_const { - FatalError.raise(); - } } impl<'a> Visitor<'a> for AstValidator<'a> { @@ -745,7 +828,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { defaultness: _, constness: _, generics: _, - of_trait: Some(_), + of_trait: Some(ref t), ref self_ty, items: _, } => { @@ -760,13 +843,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .help("use `auto trait Trait {}` instead") .emit(); } - if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) { + if let (Unsafe::Yes(span), ImplPolarity::Negative(sp)) = (unsafety, polarity) { struct_span_err!( this.session, - item.span, + sp.to(t.path.span), E0198, "negative impls cannot be unsafe" ) + .span_label(sp, "negative because of this") .span_label(span, "unsafe because of this") .emit(); } @@ -782,41 +866,42 @@ impl<'a> Visitor<'a> for AstValidator<'a> { constness, generics: _, of_trait: None, - self_ty: _, + ref self_ty, items: _, } => { + let error = |annotation_span, annotation| { + let mut err = self.err_handler().struct_span_err( + self_ty.span, + &format!("inherent impls cannot be {}", annotation), + ); + err.span_label(annotation_span, &format!("{} because of this", annotation)); + err.span_label(self_ty.span, "inherent impl for this type"); + err + }; + self.invalid_visibility( &item.vis, Some("place qualifiers on individual impl items instead"), ); if let Unsafe::Yes(span) = unsafety { - struct_span_err!( - self.session, - item.span, - E0197, - "inherent impls cannot be unsafe" - ) - .span_label(span, "unsafe because of this") - .emit(); + error(span, "unsafe").code(error_code!(E0197)).emit(); } - if polarity == ImplPolarity::Negative { - self.err_handler().span_err(item.span, "inherent impls cannot be negative"); + if let ImplPolarity::Negative(span) = polarity { + error(span, "negative").emit(); } - if defaultness == Defaultness::Default { - self.err_handler() - .struct_span_err(item.span, "inherent impls cannot be default") - .note("only trait implementations may be annotated with default") + if let Defaultness::Default(def_span) = defaultness { + error(def_span, "`default`") + .note("only trait implementations may be annotated with `default`") .emit(); } if let Const::Yes(span) = constness { - self.err_handler() - .struct_span_err(item.span, "inherent impls cannot be `const`") - .span_label(span, "`const` because of this") + error(span, "`const`") .note("only trait implementations may be annotated with `const`") .emit(); } } - ItemKind::Fn(ref sig, ref generics, ref body) => { + ItemKind::Fn(def, ref sig, ref generics, ref body) => { + self.check_defaultness(item.span, def); self.check_const_fn_const_generic(item.span, sig, generics); if body.is_none() { @@ -845,33 +930,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => { if is_auto == IsAuto::Yes { // Auto traits cannot have generics, super traits nor contain items. - if !generics.params.is_empty() { - struct_span_err!( - self.session, - item.span, - E0567, - "auto traits cannot have generic parameters" - ) - .emit(); - } - if !bounds.is_empty() { - struct_span_err!( - self.session, - item.span, - E0568, - "auto traits cannot have super traits" - ) - .emit(); - } - if !trait_items.is_empty() { - struct_span_err!( - self.session, - item.span, - E0380, - "auto traits cannot have methods or associated items" - ) - .emit(); - } + self.deny_generic_params(generics, item.ident.span); + self.deny_super_traits(bounds, item.ident.span); + self.deny_items(trait_items, item.ident.span); } self.no_questions_in_bounds(bounds, "supertraits", true); @@ -900,6 +961,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.err_handler().span_err(item.span, "unions cannot have zero fields"); } } + ItemKind::Const(def, .., None) => { + self.check_defaultness(item.span, def); + let msg = "free constant item without body"; + self.error_item_without_body(item.span, "constant", msg, " = ;"); + } + ItemKind::Static(.., None) => { + let msg = "free static item without body"; + self.error_item_without_body(item.span, "static", msg, " = ;"); + } + ItemKind::TyAlias(def, _, ref bounds, ref body) => { + self.check_defaultness(item.span, def); + if body.is_none() { + let msg = "free type alias without body"; + self.error_item_without_body(item.span, "type", msg, " = ;"); + } + self.check_type_no_bounds(bounds, "this context"); + } _ => {} } @@ -908,11 +986,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { match &fi.kind { - ForeignItemKind::Fn(sig, _, body) => { + ForeignItemKind::Fn(def, sig, _, body) => { + self.check_defaultness(fi.span, *def); self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header); } - ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {} + ForeignItemKind::TyAlias(def, generics, bounds, body) => { + self.check_defaultness(fi.span, *def); + self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span)); + self.check_type_no_bounds(bounds, "`extern` blocks"); + self.check_foreign_ty_genericless(generics); + } + ForeignItemKind::Static(_, _, body) => { + self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span)); + } + ForeignItemKind::MacCall(..) => {} } visit::walk_foreign_item(self, fi) @@ -923,24 +1011,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match *generic_args { GenericArgs::AngleBracketed(ref data) => { walk_list!(self, visit_generic_arg, &data.args); - validate_generics_order( - self.session, - self.err_handler(), - data.args.iter().map(|arg| { - ( - match arg { - GenericArg::Lifetime(..) => ParamKindOrd::Lifetime, - GenericArg::Type(..) => ParamKindOrd::Type, - GenericArg::Const(..) => ParamKindOrd::Const, - }, - None, - arg.span(), - None, - ) - }), - GenericPosition::Arg, - generic_args.span(), - ); // Type bindings such as `Item = impl Debug` in `Iterator` // are allowed to contain nested `impl Trait`. @@ -954,7 +1024,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } GenericArgs::Parenthesized(ref data) => { walk_list!(self, visit_ty, &data.inputs); - if let FunctionRetTy::Ty(ty) = &data.output { + if let FnRetTy::Ty(ty) = &data.output { // `-> Foo` syntax is essentially an associated type binding, // so it is also allowed to contain nested `impl Trait`. self.with_impl_trait(None, |this| this.visit_ty(ty)); @@ -977,7 +1047,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } - validate_generics_order( + validate_generic_param_order( self.session, self.err_handler(), generics.params.iter().map(|param| { @@ -992,7 +1062,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }; (kind, Some(&*param.bounds), param.ident.span, ident) }), - GenericPosition::Param, generics.span, ); @@ -1108,9 +1177,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }) = fk.header() { self.err_handler() - .struct_span_err(span, "functions cannot be both `const` and `async`") + .struct_span_err( + vec![*cspan, *aspan], + "functions cannot be both `const` and `async`", + ) .span_label(*cspan, "`const` because of this") .span_label(*aspan, "`async` because of this") + .span_label(span, "") // Point at the fn header. .emit(); } @@ -1145,21 +1218,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) { - if ctxt == AssocCtxt::Trait { - self.check_defaultness(item.span, item.defaultness); + if ctxt == AssocCtxt::Trait || !self.in_trait_impl { + self.check_defaultness(item.span, item.kind.defaultness()); } if ctxt == AssocCtxt::Impl { match &item.kind { - AssocItemKind::Const(_, body) => { + AssocItemKind::Const(_, _, body) => { self.check_impl_item_provided(item.span, body, "constant", " = ;"); } - AssocItemKind::Fn(_, body) => { + AssocItemKind::Fn(_, _, _, body) => { self.check_impl_item_provided(item.span, body, "function", " { }"); } - AssocItemKind::TyAlias(bounds, body) => { + AssocItemKind::TyAlias(_, _, bounds, body) => { self.check_impl_item_provided(item.span, body, "type", " = ;"); - self.check_impl_assoc_type_no_bounds(bounds); + self.check_type_no_bounds(bounds, "`impl`s"); } _ => {} } @@ -1167,12 +1240,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if ctxt == AssocCtxt::Trait || self.in_trait_impl { self.invalid_visibility(&item.vis, None); - if let AssocItemKind::Fn(sig, _) = &item.kind { + if let AssocItemKind::Fn(_, sig, _, _) = &item.kind { self.check_trait_fn_not_const(sig.header.constness); self.check_trait_fn_not_async(item.span, sig.header.asyncness); } } + if let AssocItemKind::Const(..) = item.kind { + self.check_item_named(item.ident, "const"); + } + self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt)); } } diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index 0b21de4d78b..364c86bd99b 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -1,3 +1,7 @@ +use rustc_ast::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId}; +use rustc_ast::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}; +use rustc_ast::attr; +use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_errors::{struct_span_err, Handler}; use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; use rustc_feature::{Features, GateIssue, UnstableFeatures}; @@ -5,10 +9,6 @@ use rustc_session::parse::{feature_err, feature_err_issue, ParseSess}; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; -use syntax::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId}; -use syntax::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}; -use syntax::attr; -use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use log::debug; @@ -245,7 +245,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { include => external_doc cfg => doc_cfg masked => doc_masked - spotlight => doc_spotlight alias => doc_alias keyword => doc_keyword ); @@ -338,18 +337,18 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::Impl { polarity, defaultness, .. } => { - if polarity == ast::ImplPolarity::Negative { + ast::ItemKind::Impl { polarity, defaultness, ref of_trait, .. } => { + if let ast::ImplPolarity::Negative(span) = polarity { gate_feature_post!( &self, optin_builtin_traits, - i.span, + span.to(of_trait.as_ref().map(|t| t.path.span).unwrap_or(span)), "negative trait bounds are not yet fully implemented; \ - use marker types for now" + use marker types for now" ); } - if let ast::Defaultness::Default = defaultness { + if let ast::Defaultness::Default(_) = defaultness { gate_feature_post!(&self, specialization, i.span, "specialization is unstable"); } } @@ -367,12 +366,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, trait_alias, i.span, "trait aliases are experimental"); } - ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { + ast::ItemKind::MacroDef(ast::MacroDef { macro_rules: false, .. }) => { let msg = "`macro` is experimental"; gate_feature_post!(&self, decl_macro, i.span, msg); } - ast::ItemKind::TyAlias(ref ty, ..) => self.check_impl_trait(&ty), + ast::ItemKind::TyAlias(_, _, _, Some(ref ty)) => self.check_impl_trait(&ty), _ => {} } @@ -397,10 +396,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } } - ast::ForeignItemKind::Ty => { + ast::ForeignItemKind::TyAlias(..) => { gate_feature_post!(&self, extern_types, i.span, "extern types are experimental"); } - ast::ForeignItemKind::Macro(..) => {} + ast::ForeignItemKind::MacCall(..) => {} } visit::walk_foreign_item(self, i) @@ -419,8 +418,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_ty(self, ty) } - fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) { - if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty { + fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) { + if let ast::FnRetTy::Ty(ref output_ty) = *ret_ty { if let ast::TyKind::Never = output_ty.kind { // Do nothing. } else { @@ -543,17 +542,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { - if i.defaultness == ast::Defaultness::Default { - gate_feature_post!(&self, specialization, i.span, "specialization is unstable"); - } - - match i.kind { - ast::AssocItemKind::Fn(ref sig, _) => { + let is_fn = match i.kind { + ast::AssocItemKind::Fn(_, ref sig, _, _) => { if let (ast::Const::Yes(_), AssocCtxt::Trait) = (sig.header.constness, ctxt) { gate_feature_post!(&self, const_fn, i.span, "const fn is unstable"); } + true } - ast::AssocItemKind::TyAlias(_, ref ty) => { + ast::AssocItemKind::TyAlias(_, ref generics, _, ref ty) => { if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { gate_feature_post!( &self, @@ -565,9 +561,20 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if let Some(ty) = ty { self.check_impl_trait(ty); } - self.check_gat(&i.generics, i.span); + self.check_gat(generics, i.span); + false } - _ => {} + _ => false, + }; + if let ast::Defaultness::Default(_) = i.kind.defaultness() { + // Limit `min_specialization` to only specializing functions. + gate_feature_fn!( + &self, + |x: &Features| x.specialization || (is_fn && x.min_specialization), + i.span, + sym::specialization, + "specialization is unstable" + ); } visit::walk_assoc_item(self, i, ctxt) } diff --git a/src/librustc_ast_passes/lib.rs b/src/librustc_ast_passes/lib.rs index 520a7ac3e56..10081d36754 100644 --- a/src/librustc_ast_passes/lib.rs +++ b/src/librustc_ast_passes/lib.rs @@ -1,3 +1,4 @@ +#![feature(bindings_after_at)] //! The `rustc_ast_passes` crate contains passes which validate the AST in `syntax` //! parsed by `rustc_parse` and then lowered, after the passes in this crate, //! by `rustc_ast_lowering`. diff --git a/src/librustc_ast_passes/node_count.rs b/src/librustc_ast_passes/node_count.rs index ed1ccdf6a76..534d6c7b1ea 100644 --- a/src/librustc_ast_passes/node_count.rs +++ b/src/librustc_ast_passes/node_count.rs @@ -1,8 +1,8 @@ // Simply gives a rought count of the number of nodes in an AST. +use rustc_ast::ast::*; +use rustc_ast::visit::*; use rustc_span::Span; -use syntax::ast::*; -use syntax::visit::*; pub struct NodeCounter { pub count: usize, @@ -113,7 +113,7 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_lifetime(self, lifetime) } - fn visit_mac(&mut self, _mac: &Mac) { + fn visit_mac(&mut self, _mac: &MacCall) { self.count += 1; walk_mac(self, _mac) } diff --git a/src/librustc_ast_passes/show_span.rs b/src/librustc_ast_passes/show_span.rs index 4596e8ff53d..2366426d4dc 100644 --- a/src/librustc_ast_passes/show_span.rs +++ b/src/librustc_ast_passes/show_span.rs @@ -5,9 +5,9 @@ use std::str::FromStr; -use syntax::ast; -use syntax::visit; -use syntax::visit::Visitor; +use rustc_ast::ast; +use rustc_ast::visit; +use rustc_ast::visit::Visitor; enum Mode { Expression, @@ -55,7 +55,7 @@ impl<'a> Visitor<'a> for ShowSpanVisitor<'a> { visit::walk_ty(self, t); } - fn visit_mac(&mut self, mac: &'a ast::Mac) { + fn visit_mac(&mut self, mac: &'a ast::MacCall) { visit::walk_mac(self, mac); } } diff --git a/src/librustc_ast_pretty/Cargo.toml b/src/librustc_ast_pretty/Cargo.toml index 2f7f804b628..82be095db88 100644 --- a/src/librustc_ast_pretty/Cargo.toml +++ b/src/librustc_ast_pretty/Cargo.toml @@ -13,4 +13,4 @@ doctest = false log = "0.4" rustc_span = { path = "../librustc_span" } rustc_data_structures = { path = "../librustc_data_structures" } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index b1fa818d0a8..bb73e982a9c 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1,19 +1,19 @@ use crate::pp::Breaks::{Consistent, Inconsistent}; use crate::pp::{self, Breaks}; +use rustc_ast::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; +use rustc_ast::ast::{Attribute, GenericArg, MacArgs}; +use rustc_ast::ast::{GenericBound, SelfKind, TraitBoundModifier}; +use rustc_ast::attr; +use rustc_ast::ptr::P; +use rustc_ast::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind}; +use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; +use rustc_ast::util::parser::{self, AssocOp, Fixity}; +use rustc_ast::util::{classify, comments}; use rustc_span::edition::Edition; -use rustc_span::source_map::{dummy_spanned, SourceMap, Spanned}; -use rustc_span::symbol::{kw, sym}; +use rustc_span::source_map::{SourceMap, Spanned}; +use rustc_span::symbol::{kw, sym, IdentPrinter}; use rustc_span::{BytePos, FileName, Span}; -use syntax::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; -use syntax::ast::{Attribute, GenericArg, MacArgs}; -use syntax::ast::{GenericBound, SelfKind, TraitBoundModifier}; -use syntax::attr; -use syntax::ptr::P; -use syntax::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind}; -use syntax::tokenstream::{self, TokenStream, TokenTree}; -use syntax::util::parser::{self, AssocOp, Fixity}; -use syntax::util::{classify, comments}; use std::borrow::Cow; @@ -47,15 +47,15 @@ pub struct NoAnn; impl PpAnn for NoAnn {} pub struct Comments<'a> { - cm: &'a SourceMap, + sm: &'a SourceMap, comments: Vec, current: usize, } impl<'a> Comments<'a> { - pub fn new(cm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> { - let comments = comments::gather_comments(cm, filename, input); - Comments { cm, comments, current: 0 } + pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> { + let comments = comments::gather_comments(sm, filename, input); + Comments { sm, comments, current: 0 } } pub fn next(&self) -> Option { @@ -71,8 +71,8 @@ impl<'a> Comments<'a> { if cmnt.style != comments::Trailing { return None; } - let span_line = self.cm.lookup_char_pos(span.hi()); - let comment_line = self.cm.lookup_char_pos(cmnt.pos); + let span_line = self.sm.lookup_char_pos(span.hi()); + let comment_line = self.sm.lookup_char_pos(cmnt.pos); let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1)); if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line { return Some(cmnt); @@ -95,7 +95,7 @@ crate const INDENT_UNIT: usize = 4; /// Requires you to pass an input filename and reader so that /// it can scan the input text for comments to copy forward. pub fn print_crate<'a>( - cm: &'a SourceMap, + sm: &'a SourceMap, krate: &ast::Crate, filename: FileName, input: String, @@ -106,7 +106,7 @@ pub fn print_crate<'a>( ) -> String { let mut s = State { s: pp::mk_printer(), - comments: Some(Comments::new(cm, filename, input)), + comments: Some(Comments::new(sm, filename, input)), ann, is_expanded, }; @@ -148,12 +148,19 @@ pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { // This makes comma-separated lists look slightly nicer, // and also addresses a specific regression described in issue #63896. -fn tt_prepend_space(tt: &TokenTree) -> bool { +fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { match tt { TokenTree::Token(token) => match token.kind { token::Comma => false, _ => true, }, + TokenTree::Delimited(_, DelimToken::Paren, _) => match prev { + TokenTree::Token(token) => match token.kind { + token::Ident(_, _) => false, + _ => true, + }, + _ => true, + }, _ => true, } } @@ -196,40 +203,6 @@ pub fn literal_to_string(lit: token::Lit) -> String { out } -/// Print an ident from AST, `$crate` is converted into its respective crate name. -pub fn ast_ident_to_string(ident: ast::Ident, is_raw: bool) -> String { - ident_to_string(ident.name, is_raw, Some(ident.span)) -} - -// AST pretty-printer is used as a fallback for turning AST structures into token streams for -// proc macros. Additionally, proc macros may stringify their input and expect it survive the -// stringification (especially true for proc macro derives written between Rust 1.15 and 1.30). -// So we need to somehow pretty-print `$crate` in a way preserving at least some of its -// hygiene data, most importantly name of the crate it refers to. -// As a result we print `$crate` as `crate` if it refers to the local crate -// and as `::other_crate_name` if it refers to some other crate. -// Note, that this is only done if the ident token is printed from inside of AST pretty-pringing, -// but not otherwise. Pretty-printing is the only way for proc macros to discover token contents, -// so we should not perform this lossy conversion if the top level call to the pretty-printer was -// done for a token stream or a single token. -fn ident_to_string(name: ast::Name, is_raw: bool, convert_dollar_crate: Option) -> String { - if is_raw { - format!("r#{}", name) - } else { - if name == kw::DollarCrate { - if let Some(span) = convert_dollar_crate { - let converted = span.ctxt().dollar_crate_name(); - return if converted.is_path_segment_keyword() { - converted.to_string() - } else { - format!("::{}", converted) - }; - } - } - name.to_string() - } -} - /// Print the token kind precisely, without converting `$crate` into its respective crate name. pub fn token_kind_to_string(tok: &TokenKind) -> String { token_kind_to_string_ext(tok, None) @@ -280,7 +253,7 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option) token::Literal(lit) => literal_to_string(lit), /* Name components */ - token::Ident(s, is_raw) => ident_to_string(s, is_raw, convert_dollar_crate), + token::Ident(s, is_raw) => IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string(), token::Lifetime(s) => s.to_string(), /* Other */ @@ -315,14 +288,11 @@ pub fn nonterminal_to_string(nt: &Nonterminal) -> String { token::NtBlock(ref e) => block_to_string(e), token::NtStmt(ref e) => stmt_to_string(e), token::NtPat(ref e) => pat_to_string(e), - token::NtIdent(e, is_raw) => ast_ident_to_string(e, is_raw), + token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(), token::NtLifetime(e) => e.to_string(), token::NtLiteral(ref e) => expr_to_string(e), token::NtTT(ref tree) => tt_to_string(tree.clone()), - // FIXME(Centril): merge these variants. - token::NtImplItem(ref e) | token::NtTraitItem(ref e) => assoc_item_to_string(e), token::NtVis(ref e) => vis_to_string(e), - token::NtForeignItem(ref e) => foreign_item_to_string(e), } } @@ -358,10 +328,6 @@ pub fn item_to_string(i: &ast::Item) -> String { to_string(|s| s.print_item(i)) } -fn assoc_item_to_string(i: &ast::AssocItem) -> String { - to_string(|s| s.print_assoc_item(i)) -} - pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String { to_string(|s| s.print_generic_params(generic_params)) } @@ -404,10 +370,6 @@ pub fn param_to_string(arg: &ast::Param) -> String { to_string(|s| s.print_param(arg, false)) } -fn foreign_item_to_string(arg: &ast::ForeignItem) -> String { - to_string(|s| s.print_foreign_item(arg)) -} - fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { format!("{}{}", to_string(|s| s.print_visibility(vis)), s) } @@ -522,8 +484,8 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.hardbreak(); } } - if let Some(cm) = self.comments() { - cm.current += 1; + if let Some(cmnts) = self.comments() { + cmnts.current += 1; } } @@ -695,11 +657,14 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } fn print_tts(&mut self, tts: tokenstream::TokenStream, convert_dollar_crate: bool) { - for (i, tt) in tts.into_trees().enumerate() { - if i != 0 && tt_prepend_space(&tt) { + let mut iter = tts.into_trees().peekable(); + while let Some(tt) = iter.next() { + let show_space = + if let Some(next) = iter.peek() { tt_prepend_space(next, &tt) } else { false }; + self.print_tt(tt, convert_dollar_crate); + if show_space { self.space(); } - self.print_tt(tt, convert_dollar_crate); } } @@ -819,7 +784,7 @@ impl<'a> PrintState<'a> for State<'a> { } fn print_ident(&mut self, ident: ast::Ident) { - self.s.word(ast_ident_to_string(ident, ident.is_raw_guess())); + self.s.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string()); self.ann.post(self, AnnNode::Ident(&ident)) } @@ -836,7 +801,7 @@ impl<'a> PrintState<'a> for State<'a> { s.print_generic_arg(generic_arg) }); - let mut comma = data.args.len() != 0; + let mut comma = !data.args.is_empty(); for constraint in data.constraints.iter() { if comma { @@ -912,7 +877,7 @@ impl<'a> State<'a> { } } - crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) { + crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[Attribute]) { self.print_inner_attributes(attrs); for item in &nmod.items { self.print_foreign_item(item); @@ -1005,7 +970,7 @@ impl<'a> State<'a> { ast::TyKind::ImplicitSelf => { self.s.word("Self"); } - ast::TyKind::Mac(ref m) => { + ast::TyKind::MacCall(ref m) => { self.print_mac(m); } ast::TyKind::CVarArgs => { @@ -1016,59 +981,61 @@ impl<'a> State<'a> { } crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) { + let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; + self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); - self.maybe_print_comment(item.span.lo()); - self.print_outer_attributes(&item.attrs); - match item.kind { - ast::ForeignItemKind::Fn(ref sig, ref gen, ref body) => { - self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); + self.maybe_print_comment(span.lo()); + self.print_outer_attributes(attrs); + match kind { + ast::ForeignItemKind::Fn(def, sig, gen, body) => { + self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs); } - ast::ForeignItemKind::Static(ref t, m) => { - self.head(visibility_qualified(&item.vis, "static")); - if m == ast::Mutability::Mut { - self.word_space("mut"); - } - self.print_ident(item.ident); - self.word_space(":"); - self.print_type(t); - self.s.word(";"); - self.end(); // end the head-ibox - self.end(); // end the outer cbox + ast::ForeignItemKind::Static(ty, mutbl, body) => { + let def = ast::Defaultness::Final; + self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def); } - ast::ForeignItemKind::Ty => { - self.head(visibility_qualified(&item.vis, "type")); - self.print_ident(item.ident); - self.s.word(";"); - self.end(); // end the head-ibox - self.end(); // end the outer cbox + ast::ForeignItemKind::TyAlias(def, generics, bounds, ty) => { + self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def); } - ast::ForeignItemKind::Macro(ref m) => { + ast::ForeignItemKind::MacCall(m) => { self.print_mac(m); if m.args.need_semicolon() { self.s.word(";"); } } } + self.ann.post(self, AnnNode::SubItem(id)) } - fn print_associated_const( + fn print_item_const( &mut self, ident: ast::Ident, + mutbl: Option, ty: &ast::Ty, - default: Option<&ast::Expr>, + body: Option<&ast::Expr>, vis: &ast::Visibility, + defaultness: ast::Defaultness, ) { - self.s.word(visibility_qualified(vis, "")); - self.word_space("const"); + self.head(""); + self.print_visibility(vis); + self.print_defaultness(defaultness); + let leading = match mutbl { + None => "const", + Some(ast::Mutability::Not) => "static", + Some(ast::Mutability::Mut) => "static mut", + }; + self.word_space(leading); self.print_ident(ident); self.word_space(":"); self.print_type(ty); - if let Some(expr) = default { - self.s.space(); + self.s.space(); + self.end(); // end the head-ibox + if let Some(body) = body { self.word_space("="); - self.print_expr(expr); + self.print_expr(body); } - self.s.word(";") + self.s.word(";"); + self.end(); // end the outer cbox } fn print_associated_type( @@ -1077,7 +1044,12 @@ impl<'a> State<'a> { generics: &ast::Generics, bounds: &ast::GenericBounds, ty: Option<&ast::Ty>, + vis: &ast::Visibility, + defaultness: ast::Defaultness, ) { + self.head(""); + self.print_visibility(vis); + self.print_defaultness(defaultness); self.word_space("type"); self.print_ident(ident); self.print_generic_params(&generics.params); @@ -1088,7 +1060,9 @@ impl<'a> State<'a> { self.word_space("="); self.print_type(ty); } - self.s.word(";") + self.s.word(";"); + self.end(); // end inner head-block + self.end(); // end outer head-block } /// Pretty-prints an item. @@ -1118,37 +1092,16 @@ impl<'a> State<'a> { self.end(); // end inner head-block self.end(); // end outer head-block } - ast::ItemKind::Static(ref ty, m, ref expr) => { - self.head(visibility_qualified(&item.vis, "static")); - if m == ast::Mutability::Mut { - self.word_space("mut"); - } - self.print_ident(item.ident); - self.word_space(":"); - self.print_type(ty); - self.s.space(); - self.end(); // end the head-ibox - - self.word_space("="); - self.print_expr(expr); - self.s.word(";"); - self.end(); // end the outer cbox + ast::ItemKind::Static(ref ty, mutbl, ref body) => { + let def = ast::Defaultness::Final; + self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def); } - ast::ItemKind::Const(ref ty, ref expr) => { - self.head(visibility_qualified(&item.vis, "const")); - self.print_ident(item.ident); - self.word_space(":"); - self.print_type(ty); - self.s.space(); - self.end(); // end the head-ibox - - self.word_space("="); - self.print_expr(expr); - self.s.word(";"); - self.end(); // end the outer cbox + ast::ItemKind::Const(def, ref ty, ref body) => { + self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def); } - ast::ItemKind::Fn(ref sig, ref gen, ref body) => { - self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs); + ast::ItemKind::Fn(def, ref sig, ref gen, ref body) => { + let body = body.as_deref(); + self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs); } ast::ItemKind::Mod(ref _mod) => { self.head(visibility_qualified(&item.vis, "mod")); @@ -1180,18 +1133,9 @@ impl<'a> State<'a> { self.s.word(ga.asm.to_string()); self.end(); } - ast::ItemKind::TyAlias(ref ty, ref generics) => { - self.head(visibility_qualified(&item.vis, "type")); - self.print_ident(item.ident); - self.print_generic_params(&generics.params); - self.end(); // end the inner ibox - - self.print_where_clause(&generics.where_clause); - self.s.space(); - self.word_space("="); - self.print_type(ty); - self.s.word(";"); - self.end(); // end the outer ibox + ast::ItemKind::TyAlias(def, ref generics, ref bounds, ref ty) => { + let ty = ty.as_deref(); + self.print_associated_type(item.ident, generics, bounds, ty, &item.vis, def); } ast::ItemKind::Enum(ref enum_definition, ref params) => { self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis); @@ -1226,7 +1170,7 @@ impl<'a> State<'a> { self.s.space(); } - if polarity == ast::ImplPolarity::Negative { + if let ast::ImplPolarity::Negative(_) = polarity { self.s.word("!"); } @@ -1269,6 +1213,7 @@ impl<'a> State<'a> { self.print_where_clause(&generics.where_clause); self.s.word(" "); self.bopen(); + self.print_inner_attributes(&item.attrs); for trait_item in trait_items { self.print_assoc_item(trait_item); } @@ -1296,14 +1241,14 @@ impl<'a> State<'a> { self.print_where_clause(&generics.where_clause); self.s.word(";"); } - ast::ItemKind::Mac(ref mac) => { + ast::ItemKind::MacCall(ref mac) => { self.print_mac(mac); if mac.args.need_semicolon() { self.s.word(";"); } } ast::ItemKind::MacroDef(ref macro_def) => { - let (kw, has_bang) = if macro_def.legacy { + let (kw, has_bang) = if macro_def.macro_rules { ("macro_rules", true) } else { self.print_visibility(&item.vis); @@ -1391,7 +1336,7 @@ impl<'a> State<'a> { } crate fn print_defaultness(&mut self, defaultness: ast::Defaultness) { - if let ast::Defaultness::Default = defaultness { + if let ast::Defaultness::Default(_) = defaultness { self.word_nbsp("default"); } } @@ -1463,30 +1408,29 @@ impl<'a> State<'a> { } crate fn print_assoc_item(&mut self, item: &ast::AssocItem) { - self.ann.pre(self, AnnNode::SubItem(item.id)); + let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item; + self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); - self.maybe_print_comment(item.span.lo()); - self.print_outer_attributes(&item.attrs); - self.print_defaultness(item.defaultness); - match &item.kind { - ast::AssocItemKind::Const(ty, expr) => { - self.print_associated_const(item.ident, ty, expr.as_deref(), &item.vis); + self.maybe_print_comment(span.lo()); + self.print_outer_attributes(attrs); + match kind { + ast::AssocItemKind::Fn(def, sig, gen, body) => { + self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs); } - ast::AssocItemKind::Fn(sig, body) => { - let body = body.as_deref(); - self.print_fn_full(sig, item.ident, &item.generics, &item.vis, body, &item.attrs); + ast::AssocItemKind::Const(def, ty, body) => { + self.print_item_const(ident, None, ty, body.as_deref(), vis, *def); } - ast::AssocItemKind::TyAlias(bounds, ty) => { - self.print_associated_type(item.ident, &item.generics, bounds, ty.as_deref()); + ast::AssocItemKind::TyAlias(def, generics, bounds, ty) => { + self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def); } - ast::AssocItemKind::Macro(mac) => { - self.print_mac(mac); - if mac.args.need_semicolon() { + ast::AssocItemKind::MacCall(m) => { + self.print_mac(m); + if m.args.need_semicolon() { self.s.word(";"); } } } - self.ann.post(self, AnnNode::SubItem(item.id)) + self.ann.post(self, AnnNode::SubItem(id)) } crate fn print_stmt(&mut self, st: &ast::Stmt) { @@ -1518,21 +1462,15 @@ impl<'a> State<'a> { } } ast::StmtKind::Semi(ref expr) => { - match expr.kind { - // Filter out empty `Tup` exprs created for the `redundant_semicolon` - // lint, as they shouldn't be visible and interact poorly - // with proc macros. - ast::ExprKind::Tup(ref exprs) if exprs.is_empty() && expr.attrs.is_empty() => { - () - } - _ => { - self.space_if_not_bol(); - self.print_expr_outer_attr_style(expr, false); - self.s.word(";"); - } - } + self.space_if_not_bol(); + self.print_expr_outer_attr_style(expr, false); + self.s.word(";"); + } + ast::StmtKind::Empty => { + self.space_if_not_bol(); + self.s.word(";"); } - ast::StmtKind::Mac(ref mac) => { + ast::StmtKind::MacCall(ref mac) => { let (ref mac, style, ref attrs) = **mac; self.space_if_not_bol(); self.print_outer_attributes(attrs); @@ -1642,7 +1580,7 @@ impl<'a> State<'a> { self.print_else(elseopt) } - crate fn print_mac(&mut self, m: &ast::Mac) { + crate fn print_mac(&mut self, m: &ast::MacCall) { self.print_mac_common( Some(MacHeader::Path(&m.path)), true, @@ -2142,7 +2080,7 @@ impl<'a> State<'a> { self.pclose(); } - ast::ExprKind::Mac(ref m) => self.print_mac(m), + ast::ExprKind::MacCall(ref m) => self.print_mac(m), ast::ExprKind::Paren(ref e) => { self.popen(); self.print_inner_attributes_inline(attrs); @@ -2326,7 +2264,7 @@ impl<'a> State<'a> { self.print_pat(inner); self.pclose(); } - PatKind::Mac(ref m) => self.print_mac(m), + PatKind::MacCall(ref m) => self.print_mac(m), } self.ann.post(self, AnnNode::Pat(pat)) } @@ -2400,13 +2338,16 @@ impl<'a> State<'a> { name: ast::Ident, generics: &ast::Generics, vis: &ast::Visibility, + defaultness: ast::Defaultness, body: Option<&ast::Block>, attrs: &[ast::Attribute], ) { if body.is_some() { self.head(""); } - self.print_fn(&sig.decl, sig.header, Some(name), generics, vis); + self.print_visibility(vis); + self.print_defaultness(defaultness); + self.print_fn(&sig.decl, sig.header, Some(name), generics); if let Some(body) = body { self.nbsp(); self.print_block_with_attrs(body, attrs); @@ -2421,10 +2362,8 @@ impl<'a> State<'a> { header: ast::FnHeader, name: Option, generics: &ast::Generics, - vis: &ast::Visibility, ) { - self.print_fn_header_info(header, vis); - + self.print_fn_header_info(header); if let Some(name) = name { self.nbsp(); self.print_ident(name); @@ -2672,8 +2611,8 @@ impl<'a> State<'a> { self.end(); } - crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FunctionRetTy) { - if let ast::FunctionRetTy::Ty(ty) = fn_ret_ty { + crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) { + if let ast::FnRetTy::Ty(ty) = fn_ret_ty { self.space_if_not_bol(); self.ibox(INDENT_UNIT); self.word_space("->"); @@ -2702,8 +2641,7 @@ impl<'a> State<'a> { span: rustc_span::DUMMY_SP, }; let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() }; - let vis = dummy_spanned(ast::VisibilityKind::Inherited); - self.print_fn(decl, header, name, &generics, &vis); + self.print_fn(decl, header, name, &generics); self.end(); } @@ -2730,9 +2668,7 @@ impl<'a> State<'a> { } } - crate fn print_fn_header_info(&mut self, header: ast::FnHeader, vis: &ast::Visibility) { - self.s.word(visibility_qualified(vis, "")); - + crate fn print_fn_header_info(&mut self, header: ast::FnHeader) { self.print_constness(header.constness); self.print_asyncness(header.asyncness); self.print_unsafety(header.unsafety); diff --git a/src/librustc_ast_pretty/pprust/tests.rs b/src/librustc_ast_pretty/pprust/tests.rs index 279e6f518a7..455f2e3da36 100644 --- a/src/librustc_ast_pretty/pprust/tests.rs +++ b/src/librustc_ast_pretty/pprust/tests.rs @@ -1,9 +1,9 @@ use super::*; +use rustc_ast::ast; +use rustc_ast::with_default_globals; use rustc_span; -use rustc_span::source_map::{dummy_spanned, respan}; -use syntax::ast; -use syntax::with_default_globals; +use rustc_span::source_map::respan; fn fun_to_string( decl: &ast::FnDecl, @@ -13,13 +13,7 @@ fn fun_to_string( ) -> String { to_string(|s| { s.head(""); - s.print_fn( - decl, - header, - Some(name), - generics, - &dummy_spanned(ast::VisibilityKind::Inherited), - ); + s.print_fn(decl, header, Some(name), generics); s.end(); // Close the head box. s.end(); // Close the outer box. }) @@ -34,10 +28,8 @@ fn test_fun_to_string() { with_default_globals(|| { let abba_ident = ast::Ident::from_str("abba"); - let decl = ast::FnDecl { - inputs: Vec::new(), - output: ast::FunctionRetTy::Default(rustc_span::DUMMY_SP), - }; + let decl = + ast::FnDecl { inputs: Vec::new(), output: ast::FnRetTy::Default(rustc_span::DUMMY_SP) }; let generics = ast::Generics::default(); assert_eq!( fun_to_string(&decl, ast::FnHeader::default(), abba_ident, &generics), diff --git a/src/librustc_attr/Cargo.toml b/src/librustc_attr/Cargo.toml index 83a5f41989b..8aaba15d84a 100644 --- a/src/librustc_attr/Cargo.toml +++ b/src/librustc_attr/Cargo.toml @@ -19,4 +19,4 @@ rustc_feature = { path = "../librustc_feature" } rustc_macros = { path = "../librustc_macros" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_session = { path = "../librustc_session" } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index ac1a191fa23..99083cca6cb 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -2,6 +2,7 @@ use super::{find_by_name, mark_used}; +use rustc_ast::ast::{self, Attribute, MetaItem, MetaItemKind, NestedMetaItem}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, Handler}; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; @@ -10,7 +11,6 @@ use rustc_session::parse::{feature_err, ParseSess}; use rustc_span::hygiene::Transparency; use rustc_span::{symbol::sym, symbol::Symbol, Span}; use std::num::NonZeroU32; -use syntax::ast::{self, Attribute, MetaItem, MetaItemKind, NestedMetaItem}; pub fn is_builtin_attr(attr: &Attribute) -> bool { attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some() @@ -53,7 +53,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { err.span_suggestion( span, "consider removing the prefix", - format!("{}", &lint_str[1..]), + lint_str[1..].to_string(), Applicability::MaybeIncorrect, ); } @@ -1024,7 +1024,7 @@ pub enum TransparencyError { pub fn find_transparency( attrs: &[Attribute], - is_legacy: bool, + macro_rules: bool, ) -> (Transparency, Option) { let mut transparency = None; let mut error = None; @@ -1049,7 +1049,7 @@ pub fn find_transparency( } } } - let fallback = if is_legacy { Transparency::SemiTransparent } else { Transparency::Opaque }; + let fallback = if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque }; (transparency.map_or(fallback, |t| t.0), error) } diff --git a/src/librustc_attr/lib.rs b/src/librustc_attr/lib.rs index d2ff167db88..9803501fb96 100644 --- a/src/librustc_attr/lib.rs +++ b/src/librustc_attr/lib.rs @@ -1,6 +1,6 @@ //! Functions and types dealing with attributes and meta items. //! -//! FIXME(Centril): For now being, much of the logic is still in `syntax::attr`. +//! FIXME(Centril): For now being, much of the logic is still in `rustc_ast::attr`. //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` //! to this crate. @@ -11,6 +11,6 @@ pub use IntType::*; pub use ReprAttr::*; pub use StabilityLevel::*; -pub use syntax::attr::*; +pub use rustc_ast::attr::*; -pub(crate) use syntax::HashStableContext; +pub(crate) use rustc_ast::HashStableContext; diff --git a/src/librustc_builtin_macros/Cargo.toml b/src/librustc_builtin_macros/Cargo.toml index b424ce43214..c15438bde44 100644 --- a/src/librustc_builtin_macros/Cargo.toml +++ b/src/librustc_builtin_macros/Cargo.toml @@ -21,6 +21,6 @@ rustc_parse = { path = "../librustc_parse" } rustc_target = { path = "../librustc_target" } rustc_session = { path = "../librustc_session" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } rustc_expand = { path = "../librustc_expand" } rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 4723544316f..9811a6621af 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -2,15 +2,15 @@ // use State::*; +use rustc_ast::ast::{self, AsmDialect}; +use rustc_ast::ptr::P; +use rustc_ast::token::{self, Token}; +use rustc_ast::tokenstream::{self, TokenStream}; use rustc_errors::{struct_span_err, DiagnosticBuilder, PResult}; use rustc_expand::base::*; use rustc_parse::parser::Parser; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use syntax::ast::{self, AsmDialect}; -use syntax::ptr::P; -use syntax::token::{self, Token}; -use syntax::tokenstream::{self, TokenStream}; enum State { Asm, @@ -151,7 +151,7 @@ fn parse_inline_asm<'a>( let constraint = parse_asm_str(&mut p)?; - let span = p.prev_span; + let span = p.prev_token.span; p.expect(&token::OpenDelim(token::Paren))?; let expr = p.parse_expr()?; @@ -182,7 +182,7 @@ fn parse_inline_asm<'a>( }; let is_rw = output.is_some(); - let is_indirect = constraint_str.contains("*"); + let is_indirect = constraint_str.contains('*'); outputs.push(ast::InlineAsmOutput { constraint: output.unwrap_or(constraint), expr, @@ -199,18 +199,18 @@ fn parse_inline_asm<'a>( let constraint = parse_asm_str(&mut p)?; - if constraint.as_str().starts_with("=") { + if constraint.as_str().starts_with('=') { struct_span_err!( cx.parse_sess.span_diagnostic, - p.prev_span, + p.prev_token.span, E0662, "input operand constraint contains '='" ) .emit(); - } else if constraint.as_str().starts_with("+") { + } else if constraint.as_str().starts_with('+') { struct_span_err!( cx.parse_sess.span_diagnostic, - p.prev_span, + p.prev_token.span, E0663, "input operand constraint contains '+'" ) @@ -233,11 +233,11 @@ fn parse_inline_asm<'a>( let s = parse_asm_str(&mut p)?; if OPTIONS.iter().any(|&opt| s == opt) { - cx.span_warn(p.prev_span, "expected a clobber, found an option"); - } else if s.as_str().starts_with("{") || s.as_str().ends_with("}") { + cx.span_warn(p.prev_token.span, "expected a clobber, found an option"); + } else if s.as_str().starts_with('{') || s.as_str().ends_with('}') { struct_span_err!( cx.parse_sess.span_diagnostic, - p.prev_span, + p.prev_token.span, E0664, "clobber should not be surrounded by braces" ) @@ -259,7 +259,7 @@ fn parse_inline_asm<'a>( } else if option == sym::intel { dialect = AsmDialect::Intel; } else { - cx.span_warn(p.prev_span, "unrecognized option"); + cx.span_warn(p.prev_token.span, "unrecognized option"); } if p.token == token::Comma { diff --git a/src/librustc_builtin_macros/assert.rs b/src/librustc_builtin_macros/assert.rs index 3fc86a5469c..3a3595b04d2 100644 --- a/src/librustc_builtin_macros/assert.rs +++ b/src/librustc_builtin_macros/assert.rs @@ -1,14 +1,14 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_ast::ast::{self, *}; +use rustc_ast::ptr::P; +use rustc_ast::token::{self, TokenKind}; +use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_expand::base::*; use rustc_parse::parser::Parser; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use syntax::ast::{self, *}; -use syntax::ptr::P; -use syntax::token::{self, TokenKind}; -use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree}; pub fn expand_assert<'cx>( cx: &'cx mut ExtCtxt<'_>, @@ -40,7 +40,7 @@ pub fn expand_assert<'cx>( )) }); let args = P(MacArgs::Delimited(DelimSpan::from_single(sp), MacDelimiter::Parenthesis, tokens)); - let panic_call = Mac { + let panic_call = MacCall { path: Path::from_ident(Ident::new(sym::panic, sp)), args, prior_type_ascription: None, @@ -48,7 +48,7 @@ pub fn expand_assert<'cx>( let if_expr = cx.expr_if( sp, cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)), - cx.expr(sp, ExprKind::Mac(panic_call)), + cx.expr(sp, ExprKind::MacCall(panic_call)), None, ); MacEager::expr(if_expr) @@ -80,17 +80,15 @@ fn parse_assert<'a>( // my_function(); // ); // - // Warn about semicolon and suggest removing it. Eventually, this should be turned into an - // error. + // Emit an error about semicolon and suggest removing it. if parser.token == token::Semi { - let mut err = cx.struct_span_warn(sp, "macro requires an expression as an argument"); + let mut err = cx.struct_span_err(sp, "macro requires an expression as an argument"); err.span_suggestion( parser.token.span, "try removing semicolon", String::new(), Applicability::MaybeIncorrect, ); - err.note("this is going to be an error in the future"); err.emit(); parser.bump(); @@ -101,19 +99,17 @@ fn parse_assert<'a>( // // assert!(true "error message"); // - // Parse this as an actual message, and suggest inserting a comma. Eventually, this should be - // turned into an error. + // Emit an error and suggest inserting a comma. let custom_message = if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind { - let mut err = cx.struct_span_warn(parser.token.span, "unexpected string literal"); - let comma_span = parser.prev_span.shrink_to_hi(); + let mut err = cx.struct_span_err(parser.token.span, "unexpected string literal"); + let comma_span = parser.prev_token.span.shrink_to_hi(); err.span_suggestion_short( comma_span, "try adding a comma", ", ".to_string(), Applicability::MaybeIncorrect, ); - err.note("this is going to be an error in the future"); err.emit(); parse_custom_message(&mut parser) diff --git a/src/librustc_builtin_macros/cfg.rs b/src/librustc_builtin_macros/cfg.rs index c9a77ee0acd..3c09b26af42 100644 --- a/src/librustc_builtin_macros/cfg.rs +++ b/src/librustc_builtin_macros/cfg.rs @@ -2,13 +2,13 @@ //! a literal `true` or `false` based on whether the given cfg matches the //! current compilation environment. +use rustc_ast::ast; +use rustc_ast::token; +use rustc_ast::tokenstream::TokenStream; use rustc_attr as attr; use rustc_errors::DiagnosticBuilder; use rustc_expand::base::{self, *}; use rustc_span::Span; -use syntax::ast; -use syntax::token; -use syntax::tokenstream::TokenStream; pub fn expand_cfg( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/cfg_accessible.rs b/src/librustc_builtin_macros/cfg_accessible.rs new file mode 100644 index 00000000000..3607a4d0d15 --- /dev/null +++ b/src/librustc_builtin_macros/cfg_accessible.rs @@ -0,0 +1,54 @@ +//! Implementation of the `#[cfg_accessible(path)]` attribute macro. + +use rustc_ast::ast; +use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; +use rustc_feature::AttributeTemplate; +use rustc_parse::validate_attr; +use rustc_span::symbol::sym; +use rustc_span::Span; + +crate struct Expander; + +fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> { + match mi.meta_item_list() { + None => {} + Some([]) => ecx.span_err(mi.span, "`cfg_accessible` path is not specified"), + Some([_, .., l]) => ecx.span_err(l.span(), "multiple `cfg_accessible` paths are specified"), + Some([nmi]) => match nmi.meta_item() { + None => ecx.span_err(nmi.span(), "`cfg_accessible` path cannot be a literal"), + Some(mi) => { + if !mi.is_word() { + ecx.span_err(mi.span, "`cfg_accessible` path cannot accept arguments"); + } + return Some(&mi.path); + } + }, + } + None +} + +impl MultiItemModifier for Expander { + fn expand( + &self, + ecx: &mut ExtCtxt<'_>, + _span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, + ) -> ExpandResult, Annotatable> { + let template = AttributeTemplate { list: Some("path"), ..Default::default() }; + let attr = &ecx.attribute(meta_item.clone()); + validate_attr::check_builtin_attribute(ecx.parse_sess, attr, sym::cfg_accessible, template); + + let path = match validate_input(ecx, meta_item) { + Some(path) => path, + None => return ExpandResult::Ready(Vec::new()), + }; + + let failure_msg = "cannot determine whether the path is accessible or not"; + match ecx.resolver.cfg_accessible(ecx.current_expansion.id, path) { + Ok(true) => ExpandResult::Ready(vec![item]), + Ok(false) => ExpandResult::Ready(Vec::new()), + Err(_) => ExpandResult::Retry(item, failure_msg.into()), + } + } +} diff --git a/src/librustc_builtin_macros/cmdline_attrs.rs b/src/librustc_builtin_macros/cmdline_attrs.rs index aa373d31e06..7ddbf08306b 100644 --- a/src/librustc_builtin_macros/cmdline_attrs.rs +++ b/src/librustc_builtin_macros/cmdline_attrs.rs @@ -1,11 +1,11 @@ //! Attributes injected into the crate root from command line using `-Z crate-attr`. +use rustc_ast::ast::{self, AttrItem, AttrStyle}; +use rustc_ast::attr::mk_attr; +use rustc_ast::token; use rustc_expand::panictry; use rustc_session::parse::ParseSess; use rustc_span::FileName; -use syntax::ast::{self, AttrItem, AttrStyle}; -use syntax::attr::mk_attr; -use syntax::token; pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { for raw_attr in attrs { diff --git a/src/librustc_builtin_macros/compile_error.rs b/src/librustc_builtin_macros/compile_error.rs index 4d8d168a2a8..f5955604e5f 100644 --- a/src/librustc_builtin_macros/compile_error.rs +++ b/src/librustc_builtin_macros/compile_error.rs @@ -1,8 +1,8 @@ // The compiler code necessary to support the compile_error! extension. +use rustc_ast::tokenstream::TokenStream; use rustc_expand::base::{self, *}; use rustc_span::Span; -use syntax::tokenstream::TokenStream; pub fn expand_compile_error<'cx>( cx: &'cx mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/concat.rs b/src/librustc_builtin_macros/concat.rs index ed65611da61..e0ce37b95fc 100644 --- a/src/librustc_builtin_macros/concat.rs +++ b/src/librustc_builtin_macros/concat.rs @@ -1,7 +1,7 @@ +use rustc_ast::ast; +use rustc_ast::tokenstream::TokenStream; use rustc_expand::base::{self, DummyResult}; use rustc_span::symbol::Symbol; -use syntax::ast; -use syntax::tokenstream::TokenStream; use std::string::String; @@ -49,7 +49,7 @@ pub fn expand_concat( } } } - if missing_literal.len() > 0 { + if !missing_literal.is_empty() { let mut err = cx.struct_span_err(missing_literal, "expected a literal"); err.note("only literals (like `\"foo\"`, `42` and `3.14`) can be passed to `concat!()`"); err.emit(); diff --git a/src/librustc_builtin_macros/concat_idents.rs b/src/librustc_builtin_macros/concat_idents.rs index 449cb2a0b18..b55e71b2518 100644 --- a/src/librustc_builtin_macros/concat_idents.rs +++ b/src/librustc_builtin_macros/concat_idents.rs @@ -1,10 +1,10 @@ +use rustc_ast::ast; +use rustc_ast::ptr::P; +use rustc_ast::token::{self, Token}; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_expand::base::{self, *}; use rustc_span::symbol::Symbol; use rustc_span::Span; -use syntax::ast; -use syntax::ptr::P; -use syntax::token::{self, Token}; -use syntax::tokenstream::{TokenStream, TokenTree}; pub fn expand_concat_idents<'cx>( cx: &'cx mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/deriving/bounds.rs b/src/librustc_builtin_macros/deriving/bounds.rs index ceb9aab4848..a1c818caff3 100644 --- a/src/librustc_builtin_macros/deriving/bounds.rs +++ b/src/librustc_builtin_macros/deriving/bounds.rs @@ -2,9 +2,9 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; +use rustc_ast::ast::MetaItem; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::Span; -use syntax::ast::MetaItem; pub fn expand_deriving_copy( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/deriving/clone.rs b/src/librustc_builtin_macros/deriving/clone.rs index 0df5ef3c9d8..97569ef8138 100644 --- a/src/librustc_builtin_macros/deriving/clone.rs +++ b/src/librustc_builtin_macros/deriving/clone.rs @@ -2,11 +2,11 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; +use rustc_ast::ast::{self, Expr, GenericArg, Generics, ItemKind, MetaItem, VariantData}; +use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use syntax::ast::{self, Expr, GenericArg, Generics, ItemKind, MetaItem, VariantData}; -use syntax::ptr::P; pub fn expand_deriving_clone( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/deriving/cmp/eq.rs b/src/librustc_builtin_macros/deriving/cmp/eq.rs index cb8933c1475..b39f41513ee 100644 --- a/src/librustc_builtin_macros/deriving/cmp/eq.rs +++ b/src/librustc_builtin_macros/deriving/cmp/eq.rs @@ -2,11 +2,11 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; +use rustc_ast::ast::{self, Expr, GenericArg, Ident, MetaItem}; +use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -use syntax::ast::{self, Expr, GenericArg, Ident, MetaItem}; -use syntax::ptr::P; pub fn expand_deriving_eq( cx: &mut ExtCtxt<'_>, @@ -16,8 +16,8 @@ pub fn expand_deriving_eq( push: &mut dyn FnMut(Annotatable), ) { let inline = cx.meta_word(span, sym::inline); - let hidden = syntax::attr::mk_nested_word_item(Ident::new(sym::hidden, span)); - let doc = syntax::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]); + let hidden = rustc_ast::attr::mk_nested_word_item(Ident::new(sym::hidden, span)); + let doc = rustc_ast::attr::mk_list_item(Ident::new(sym::doc, span), vec![hidden]); let attrs = vec![cx.attribute(inline), cx.attribute(doc)]; let trait_def = TraitDef { span, diff --git a/src/librustc_builtin_macros/deriving/cmp/ord.rs b/src/librustc_builtin_macros/deriving/cmp/ord.rs index fa430983806..b23fbc6f62b 100644 --- a/src/librustc_builtin_macros/deriving/cmp/ord.rs +++ b/src/librustc_builtin_macros/deriving/cmp/ord.rs @@ -2,11 +2,11 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; +use rustc_ast::ast::{self, Expr, MetaItem}; +use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; -use syntax::ast::{self, Expr, MetaItem}; -use syntax::ptr::P; pub fn expand_deriving_ord( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs b/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs index dc2912895a8..d3f1a9c15f4 100644 --- a/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs +++ b/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs @@ -2,11 +2,11 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_local, path_std}; +use rustc_ast::ast::{BinOpKind, Expr, MetaItem}; +use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; -use syntax::ast::{BinOpKind, Expr, MetaItem}; -use syntax::ptr::P; pub fn expand_deriving_partial_eq( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs b/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs index a54d8c56f75..835ccd1b022 100644 --- a/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs +++ b/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs @@ -4,11 +4,11 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_local, path_std, pathvec_std}; +use rustc_ast::ast::{self, BinOpKind, Expr, MetaItem}; +use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -use syntax::ast::{self, BinOpKind, Expr, MetaItem}; -use syntax::ptr::P; pub fn expand_deriving_partial_ord( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/deriving/debug.rs b/src/librustc_builtin_macros/deriving/debug.rs index f68fddee71b..f47be3c3c19 100644 --- a/src/librustc_builtin_macros/deriving/debug.rs +++ b/src/librustc_builtin_macros/deriving/debug.rs @@ -2,12 +2,12 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; +use rustc_ast::ast::{self, Ident}; +use rustc_ast::ast::{Expr, MetaItem}; +use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; -use syntax::ast::{self, Ident}; -use syntax::ast::{Expr, MetaItem}; -use syntax::ptr::P; pub fn expand_deriving_debug( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/deriving/decodable.rs b/src/librustc_builtin_macros/deriving/decodable.rs index 3b20ebbbab4..ac5d08ba62d 100644 --- a/src/librustc_builtin_macros/deriving/decodable.rs +++ b/src/librustc_builtin_macros/deriving/decodable.rs @@ -4,12 +4,12 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::pathvec_std; +use rustc_ast::ast; +use rustc_ast::ast::{Expr, MetaItem, Mutability}; +use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::Symbol; use rustc_span::Span; -use syntax::ast; -use syntax::ast::{Expr, MetaItem, Mutability}; -use syntax::ptr::P; pub fn expand_deriving_rustc_decodable( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/deriving/default.rs b/src/librustc_builtin_macros/deriving/default.rs index b4f059e94c1..cb85a0b1a10 100644 --- a/src/librustc_builtin_macros/deriving/default.rs +++ b/src/librustc_builtin_macros/deriving/default.rs @@ -2,12 +2,12 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; +use rustc_ast::ast::{Expr, MetaItem}; +use rustc_ast::ptr::P; use rustc_errors::struct_span_err; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; -use syntax::ast::{Expr, MetaItem}; -use syntax::ptr::P; pub fn expand_deriving_default( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/deriving/encodable.rs b/src/librustc_builtin_macros/deriving/encodable.rs index b330f00939f..9073085381a 100644 --- a/src/librustc_builtin_macros/deriving/encodable.rs +++ b/src/librustc_builtin_macros/deriving/encodable.rs @@ -89,11 +89,11 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::pathvec_std; +use rustc_ast::ast::{Expr, ExprKind, MetaItem, Mutability}; +use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::Symbol; use rustc_span::Span; -use syntax::ast::{Expr, ExprKind, MetaItem, Mutability}; -use syntax::ptr::P; pub fn expand_deriving_rustc_encodable( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs index 5cf233e222e..84ed6e96aaf 100644 --- a/src/librustc_builtin_macros/deriving/generic/mod.rs +++ b/src/librustc_builtin_macros/deriving/generic/mod.rs @@ -181,16 +181,16 @@ use std::cell::RefCell; use std::iter; use std::vec; +use rustc_ast::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind}; +use rustc_ast::ast::{GenericArg, GenericParamKind, VariantData}; +use rustc_ast::ptr::P; +use rustc_ast::util::map_in_place::MapInPlace; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_session::parse::ParseSess; use rustc_span::source_map::respan; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind}; -use syntax::ast::{GenericArg, GenericParamKind, VariantData}; -use syntax::ptr::P; -use syntax::util::map_in_place::MapInPlace; use ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty}; @@ -339,7 +339,7 @@ fn find_type_parameters( ty_param_names: &[ast::Name], cx: &ExtCtxt<'_>, ) -> Vec> { - use syntax::visit; + use rustc_ast::visit; struct Visitor<'a, 'b> { cx: &'a ExtCtxt<'b>, @@ -360,7 +360,7 @@ fn find_type_parameters( visit::walk_ty(self, ty) } - fn visit_mac(&mut self, mac: &ast::Mac) { + fn visit_mac(&mut self, mac: &ast::MacCall) { self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros"); } } @@ -482,7 +482,7 @@ impl<'a> TraitDef<'a> { }) .cloned(), ); - push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() }))) + push(Annotatable::Item(P(ast::Item { attrs, ..(*newitem).clone() }))) } _ => { // Non-Item derive is an error, but it should have been @@ -542,10 +542,10 @@ impl<'a> TraitDef<'a> { span: self.span, ident, vis: respan(self.span.shrink_to_lo(), ast::VisibilityKind::Inherited), - defaultness: ast::Defaultness::Final, attrs: Vec::new(), - generics: Generics::default(), kind: ast::AssocItemKind::TyAlias( + ast::Defaultness::Final, + Generics::default(), Vec::new(), Some(type_def.to_ty(cx, self.span, type_ident, generics)), ), @@ -588,14 +588,14 @@ impl<'a> TraitDef<'a> { span: self.span, bound_generic_params: wb.bound_generic_params.clone(), bounded_ty: wb.bounded_ty.clone(), - bounds: wb.bounds.iter().cloned().collect(), + bounds: wb.bounds.to_vec(), }) } ast::WherePredicate::RegionPredicate(ref rb) => { ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { span: self.span, lifetime: rb.lifetime, - bounds: rb.bounds.iter().cloned().collect(), + bounds: rb.bounds.to_vec(), }) } ast::WherePredicate::EqPredicate(ref we) => { @@ -689,11 +689,11 @@ impl<'a> TraitDef<'a> { attr::mark_used(&attr); let opt_trait_ref = Some(trait_ref); let unused_qual = { - let word = syntax::attr::mk_nested_word_item(Ident::new( + let word = rustc_ast::attr::mk_nested_word_item(Ident::new( Symbol::intern("unused_qualifications"), self.span, )); - let list = syntax::attr::mk_list_item(Ident::new(sym::allow, self.span), vec![word]); + let list = rustc_ast::attr::mk_list_item(Ident::new(sym::allow, self.span), vec![word]); cx.attribute(list) }; @@ -957,7 +957,7 @@ impl<'a> MethodDef<'a> { let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident); let method_ident = cx.ident_of(self.name, trait_.span); - let fn_decl = cx.fn_decl(args, ast::FunctionRetTy::Ty(ret_type)); + let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type)); let body_block = cx.block_expr(body); let unsafety = if self.is_unsafe { ast::Unsafe::Yes(trait_.span) } else { ast::Unsafe::No }; @@ -968,17 +968,16 @@ impl<'a> MethodDef<'a> { header: ast::FnHeader { unsafety, ext: ast::Extern::None, ..ast::FnHeader::default() }, decl: fn_decl, }; + let def = ast::Defaultness::Final; // Create the method. P(ast::AssocItem { id: ast::DUMMY_NODE_ID, attrs: self.attributes.clone(), - generics: fn_generics, span: trait_.span, vis: respan(trait_lo_sp, ast::VisibilityKind::Inherited), - defaultness: ast::Defaultness::Final, ident: method_ident, - kind: ast::AssocItemKind::Fn(sig, Some(body_block)), + kind: ast::AssocItemKind::Fn(def, sig, fn_generics, Some(body_block)), tokens: None, }) } diff --git a/src/librustc_builtin_macros/deriving/generic/ty.rs b/src/librustc_builtin_macros/deriving/generic/ty.rs index d2df64cac48..bd54a735311 100644 --- a/src/librustc_builtin_macros/deriving/generic/ty.rs +++ b/src/librustc_builtin_macros/deriving/generic/ty.rs @@ -4,12 +4,12 @@ pub use PtrTy::*; pub use Ty::*; +use rustc_ast::ast::{self, Expr, GenericArg, GenericParamKind, Generics, Ident, SelfKind}; +use rustc_ast::ptr::P; use rustc_expand::base::ExtCtxt; use rustc_span::source_map::{respan, DUMMY_SP}; use rustc_span::symbol::kw; use rustc_span::Span; -use syntax::ast::{self, Expr, GenericArg, GenericParamKind, Generics, Ident, SelfKind}; -use syntax::ptr::P; /// The types of pointers #[derive(Clone)] diff --git a/src/librustc_builtin_macros/deriving/hash.rs b/src/librustc_builtin_macros/deriving/hash.rs index e620711aa2b..8776e7ef507 100644 --- a/src/librustc_builtin_macros/deriving/hash.rs +++ b/src/librustc_builtin_macros/deriving/hash.rs @@ -2,11 +2,11 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{self, path_std, pathvec_std}; +use rustc_ast::ast::{Expr, MetaItem, Mutability}; +use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; -use syntax::ast::{Expr, MetaItem, Mutability}; -use syntax::ptr::P; pub fn expand_deriving_hash( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/src/librustc_builtin_macros/deriving/mod.rs index 63cd03527e1..b5ad67abf62 100644 --- a/src/librustc_builtin_macros/deriving/mod.rs +++ b/src/librustc_builtin_macros/deriving/mod.rs @@ -1,10 +1,10 @@ //! The compiler code necessary to implement the `#[derive]` extensions. -use rustc_expand::base::{Annotatable, ExtCtxt, MultiItemModifier}; +use rustc_ast::ast::{self, ItemKind, MetaItem}; +use rustc_ast::ptr::P; +use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -use syntax::ast::{self, ItemKind, MetaItem}; -use syntax::ptr::P; macro path_local($x:ident) { generic::ty::Path::new_local(stringify!($x)) @@ -48,13 +48,13 @@ impl MultiItemModifier for BuiltinDerive { span: Span, meta_item: &MetaItem, item: Annotatable, - ) -> Vec { + ) -> ExpandResult, Annotatable> { // FIXME: Built-in derives often forget to give spans contexts, // so we are doing it here in a centralized way. let span = ecx.with_def_site_ctxt(span); let mut items = Vec::new(); (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a)); - items + ExpandResult::Ready(items) } } diff --git a/src/librustc_builtin_macros/env.rs b/src/librustc_builtin_macros/env.rs index 896bb8ca053..fba76f8b496 100644 --- a/src/librustc_builtin_macros/env.rs +++ b/src/librustc_builtin_macros/env.rs @@ -3,11 +3,11 @@ // interface. // +use rustc_ast::ast::{self, GenericArg, Ident}; +use rustc_ast::tokenstream::TokenStream; use rustc_expand::base::{self, *}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use syntax::ast::{self, GenericArg, Ident}; -use syntax::tokenstream::TokenStream; use std::env; diff --git a/src/librustc_builtin_macros/format.rs b/src/librustc_builtin_macros/format.rs index a9298abe2d7..2883159a9f3 100644 --- a/src/librustc_builtin_macros/format.rs +++ b/src/librustc_builtin_macros/format.rs @@ -3,15 +3,15 @@ use Position::*; use fmt_macros as parse; +use rustc_ast::ast; +use rustc_ast::ptr::P; +use rustc_ast::token; +use rustc_ast::tokenstream::TokenStream; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, Applicability, DiagnosticBuilder}; use rustc_expand::base::{self, *}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{MultiSpan, Span}; -use syntax::ast; -use syntax::ptr::P; -use syntax::token; -use syntax::tokenstream::TokenStream; use std::borrow::Cow; use std::collections::hash_map::Entry; @@ -156,44 +156,43 @@ fn parse_args<'a>( if p.token == token::Eof { break; } // accept trailing commas - if p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq) { - named = true; - let name = if let token::Ident(name, _) = p.token.kind { + match p.token.ident() { + Some((ident, _)) if p.look_ahead(1, |t| *t == token::Eq) => { + named = true; p.bump(); - name - } else { - unreachable!(); - }; + p.expect(&token::Eq)?; + let e = p.parse_expr()?; + if let Some(prev) = names.get(&ident.name) { + ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident)) + .span_label(args[*prev].span, "previously here") + .span_label(e.span, "duplicate argument") + .emit(); + continue; + } - p.expect(&token::Eq)?; - let e = p.parse_expr()?; - if let Some(prev) = names.get(&name) { - ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", name)) - .span_label(args[*prev].span, "previously here") - .span_label(e.span, "duplicate argument") - .emit(); - continue; + // Resolve names into slots early. + // Since all the positional args are already seen at this point + // if the input is valid, we can simply append to the positional + // args. And remember the names. + let slot = args.len(); + names.insert(ident.name, slot); + args.push(e); } - - // Resolve names into slots early. - // Since all the positional args are already seen at this point - // if the input is valid, we can simply append to the positional - // args. And remember the names. - let slot = args.len(); - names.insert(name, slot); - args.push(e); - } else { - let e = p.parse_expr()?; - if named { - let mut err = ecx - .struct_span_err(e.span, "positional arguments cannot follow named arguments"); - err.span_label(e.span, "positional arguments must be before named arguments"); - for (_, pos) in &names { - err.span_label(args[*pos].span, "named argument"); + _ => { + let e = p.parse_expr()?; + if named { + let mut err = ecx.struct_span_err( + e.span, + "positional arguments cannot follow named arguments", + ); + err.span_label(e.span, "positional arguments must be before named arguments"); + for pos in names.values() { + err.span_label(args[*pos].span, "named argument"); + } + err.emit(); } - err.emit(); + args.push(e); } - args.push(e); } } Ok((fmtstr, args, names)) @@ -284,7 +283,7 @@ impl<'a, 'b> Context<'a, 'b> { err.tool_only_span_suggestion( sp, &format!("use the `{}` trait", name), - fmt.to_string(), + (*fmt).to_string(), Applicability::MaybeIncorrect, ); } @@ -359,7 +358,7 @@ impl<'a, 'b> Context<'a, 'b> { refs.sort(); refs.dedup(); let (arg_list, mut sp) = if refs.len() == 1 { - let spans: Vec<_> = spans.into_iter().filter_map(|sp| sp.map(|sp| *sp)).collect(); + let spans: Vec<_> = spans.into_iter().filter_map(|sp| sp.copied()).collect(); ( format!("argument {}", refs[0]), if spans.is_empty() { @@ -476,7 +475,7 @@ impl<'a, 'b> Context<'a, 'b> { match ty { Placeholder(_) => { // record every (position, type) combination only once - let ref mut seen_ty = self.arg_unique_types[arg]; + let seen_ty = &mut self.arg_unique_types[arg]; let i = seen_ty.iter().position(|x| *x == ty).unwrap_or_else(|| { let i = seen_ty.len(); seen_ty.push(ty); @@ -526,7 +525,7 @@ impl<'a, 'b> Context<'a, 'b> { // Map the arguments for i in 0..args_len { - let ref arg_types = self.arg_types[i]; + let arg_types = &self.arg_types[i]; let arg_offsets = arg_types.iter().map(|offset| sofar + *offset).collect::>(); self.arg_index_map.push(arg_offsets); sofar += self.arg_unique_types[i].len(); @@ -597,7 +596,7 @@ impl<'a, 'b> Context<'a, 'b> { let arg_idx = match arg_index_consumed.get_mut(i) { None => 0, // error already emitted elsewhere Some(offset) => { - let ref idx_map = self.arg_index_map[i]; + let idx_map = &self.arg_index_map[i]; // unwrap_or branch: error already emitted elsewhere let arg_idx = *idx_map.get(*offset).unwrap_or(&0); *offset += 1; @@ -721,7 +720,7 @@ impl<'a, 'b> Context<'a, 'b> { let name = names_pos[i]; let span = self.ecx.with_def_site_ctxt(e.span); pats.push(self.ecx.pat_ident(span, name)); - for ref arg_ty in self.arg_unique_types[i].iter() { + for arg_ty in self.arg_unique_types[i].iter() { locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name)); } heads.push(self.ecx.expr_addr_of(e.span, e)); @@ -894,7 +893,7 @@ pub fn expand_preparsed_format_args( }; let (is_literal, fmt_snippet) = match ecx.source_map().span_to_snippet(fmt_sp) { - Ok(s) => (s.starts_with("\"") || s.starts_with("r#"), Some(s)), + Ok(s) => (s.starts_with('"') || s.starts_with("r#"), Some(s)), _ => (false, None), }; @@ -904,7 +903,7 @@ pub fn expand_preparsed_format_args( }; /// Finds the indices of all characters that have been processed and differ between the actual - /// written code (code snippet) and the `InternedString` that get's processed in the `Parser` + /// written code (code snippet) and the `InternedString` that gets processed in the `Parser` /// in order to properly synthethise the intra-string `Span`s for error diagnostics. fn find_skips(snippet: &str, is_raw: bool) -> Vec { let mut eat_ws = false; @@ -1096,7 +1095,7 @@ pub fn expand_preparsed_format_args( cx.str_pieces.push(s); } - if cx.invalid_refs.len() >= 1 { + if !cx.invalid_refs.is_empty() { cx.report_invalid_references(numbered_position_args); } diff --git a/src/librustc_builtin_macros/global_allocator.rs b/src/librustc_builtin_macros/global_allocator.rs index 52f033e8b14..5d16be3206a 100644 --- a/src/librustc_builtin_macros/global_allocator.rs +++ b/src/librustc_builtin_macros/global_allocator.rs @@ -1,12 +1,14 @@ use crate::util::check_builtin_macro_attribute; +use rustc_ast::ast::{self, Attribute, Expr, FnHeader, FnSig, Generics, Ident, Param}; +use rustc_ast::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe}; +use rustc_ast::expand::allocator::{ + AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS, +}; +use rustc_ast::ptr::P; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use syntax::ast::{self, Attribute, Expr, FnHeader, FnSig, Generics, Ident, Param}; -use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe}; -use syntax::expand::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; -use syntax::ptr::P; pub fn expand( ecx: &mut ExtCtxt<'_>, @@ -55,18 +57,19 @@ impl AllocFnFactory<'_, '_> { fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt { let mut abi_args = Vec::new(); let mut i = 0; - let ref mut mk = || { + let mut mk = || { let name = self.cx.ident_of(&format!("arg{}", i), self.span); i += 1; name }; - let args = method.inputs.iter().map(|ty| self.arg_ty(ty, &mut abi_args, mk)).collect(); + let args = method.inputs.iter().map(|ty| self.arg_ty(ty, &mut abi_args, &mut mk)).collect(); let result = self.call_allocator(method.name, args); let (output_ty, output_expr) = self.ret_ty(&method.output, result); - let decl = self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)); + let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty)); let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() }; let sig = FnSig { decl, header }; - let kind = ItemKind::Fn(sig, Generics::default(), Some(self.cx.block_expr(output_expr))); + let block = Some(self.cx.block_expr(output_expr)); + let kind = ItemKind::Fn(ast::Defaultness::Final, sig, Generics::default(), block); let item = self.cx.item( self.span, self.cx.ident_of(&self.kind.fn_name(method.name), self.span), diff --git a/src/librustc_builtin_macros/global_asm.rs b/src/librustc_builtin_macros/global_asm.rs index 052e62ee9ff..307e7fe7121 100644 --- a/src/librustc_builtin_macros/global_asm.rs +++ b/src/librustc_builtin_macros/global_asm.rs @@ -8,15 +8,15 @@ //! LLVM's `module asm "some assembly here"`. All of LLVM's caveats //! therefore apply. +use rustc_ast::ast; +use rustc_ast::ptr::P; +use rustc_ast::token; +use rustc_ast::tokenstream::TokenStream; use rustc_errors::DiagnosticBuilder; use rustc_expand::base::{self, *}; use rustc_span::source_map::respan; use rustc_span::Span; use smallvec::smallvec; -use syntax::ast; -use syntax::ptr::P; -use syntax::token; -use syntax::tokenstream::TokenStream; pub fn expand_global_asm<'cx>( cx: &'cx mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/lib.rs b/src/librustc_builtin_macros/lib.rs index c735ba0df3b..26a59c6b1be 100644 --- a/src/librustc_builtin_macros/lib.rs +++ b/src/librustc_builtin_macros/lib.rs @@ -13,15 +13,16 @@ extern crate proc_macro; use crate::deriving::*; +use rustc_ast::ast::Ident; use rustc_expand::base::{MacroExpanderFn, Resolver, SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; use rustc_span::edition::Edition; use rustc_span::symbol::sym; -use syntax::ast::Ident; mod asm; mod assert; mod cfg; +mod cfg_accessible; mod compile_error; mod concat; mod concat_idents; @@ -85,6 +86,7 @@ pub fn register_builtin_macros(resolver: &mut dyn Resolver, edition: Edition) { register_attr! { bench: test::expand_bench, + cfg_accessible: cfg_accessible::Expander, global_allocator: global_allocator::expand, test: test::expand_test, test_case: test::expand_test_case, diff --git a/src/librustc_builtin_macros/log_syntax.rs b/src/librustc_builtin_macros/log_syntax.rs index ac7ba49ba18..ae3a889428a 100644 --- a/src/librustc_builtin_macros/log_syntax.rs +++ b/src/librustc_builtin_macros/log_syntax.rs @@ -1,6 +1,6 @@ +use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; use rustc_expand::base; -use syntax::tokenstream::TokenStream; pub fn expand_log_syntax<'cx>( _cx: &'cx mut base::ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/proc_macro_harness.rs b/src/librustc_builtin_macros/proc_macro_harness.rs index 222456d8fe0..71622a3b7e6 100644 --- a/src/librustc_builtin_macros/proc_macro_harness.rs +++ b/src/librustc_builtin_macros/proc_macro_harness.rs @@ -1,5 +1,10 @@ use std::mem; +use rustc_ast::ast::{self, Ident, NodeId}; +use rustc_ast::attr; +use rustc_ast::expand::is_proc_macro_attr; +use rustc_ast::ptr::P; +use rustc_ast::visit::{self, Visitor}; use rustc_ast_pretty::pprust; use rustc_expand::base::{ExtCtxt, Resolver}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; @@ -8,13 +13,10 @@ use rustc_span::hygiene::AstPass; use rustc_span::symbol::{kw, sym}; use rustc_span::{Span, DUMMY_SP}; use smallvec::smallvec; -use syntax::ast::{self, Ident}; -use syntax::attr; -use syntax::expand::is_proc_macro_attr; -use syntax::ptr::P; -use syntax::visit::{self, Visitor}; +use std::cell::RefCell; struct ProcMacroDerive { + id: NodeId, trait_name: ast::Name, function_name: Ident, span: Span, @@ -27,6 +29,7 @@ enum ProcMacroDefType { } struct ProcMacroDef { + id: NodeId, function_name: Ident, span: Span, def_type: ProcMacroDefType, @@ -56,7 +59,7 @@ pub fn inject( handler: &rustc_errors::Handler, ) -> ast::Crate { let ecfg = ExpansionConfig::default("proc_macro".to_string()); - let mut cx = ExtCtxt::new(sess, ecfg, resolver); + let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); let mut collect = CollectProcMacros { macros: Vec::new(), @@ -69,9 +72,6 @@ pub fn inject( if has_proc_macro_decls || is_proc_macro_crate { visit::walk_crate(&mut collect, &krate); } - // NOTE: If you change the order of macros in this vec - // for any reason, you must also update 'raw_proc_macro' - // in src/librustc_metadata/decoder.rs let macros = collect.macros; if !is_proc_macro_crate { @@ -86,7 +86,8 @@ pub fn inject( return krate; } - krate.module.items.push(mk_decls(&mut cx, ¯os)); + let decls = mk_decls(&mut krate, &mut cx, ¯os); + krate.module.items.push(decls); krate } @@ -148,7 +149,7 @@ impl<'a> CollectProcMacros<'a> { .span_err(attr.span(), "attribute must be of form: `attributes(foo, bar)`"); &[] }) - .into_iter() + .iter() .filter_map(|attr| { let attr = match attr.meta_item() { Some(meta_item) => meta_item, @@ -181,6 +182,7 @@ impl<'a> CollectProcMacros<'a> { if self.in_root && item.vis.node.is_pub() { self.macros.push(ProcMacro::Derive(ProcMacroDerive { + id: item.id, span: item.span, trait_name: trait_ident.name, function_name: item.ident, @@ -200,6 +202,7 @@ impl<'a> CollectProcMacros<'a> { fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) { if self.in_root && item.vis.node.is_pub() { self.macros.push(ProcMacro::Def(ProcMacroDef { + id: item.id, span: item.span, function_name: item.ident, def_type: ProcMacroDefType::Attr, @@ -218,6 +221,7 @@ impl<'a> CollectProcMacros<'a> { fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { if self.in_root && item.vis.node.is_pub() { self.macros.push(ProcMacro::Def(ProcMacroDef { + id: item.id, span: item.span, function_name: item.ident, def_type: ProcMacroDefType::Bang, @@ -337,7 +341,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { self.in_root = prev_in_root; } - fn visit_mac(&mut self, mac: &'a ast::Mac) { + fn visit_mac(&mut self, mac: &'a ast::MacCall) { visit::walk_mac(self, mac) } } @@ -357,7 +361,15 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // // ... // ]; // } -fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { +fn mk_decls( + ast_krate: &mut ast::Crate, + cx: &mut ExtCtxt<'_>, + macros: &[ProcMacro], +) -> P { + // We're the ones filling in this Vec, + // so it should be empty to start with + assert!(ast_krate.proc_macros.is_empty()); + let expn_id = cx.resolver.expansion_for_ast_pass( DUMMY_SP, AstPass::ProcMacroHarness, @@ -376,6 +388,12 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { let attr = cx.ident_of("attr", span); let bang = cx.ident_of("bang", span); + let krate_ref = RefCell::new(ast_krate); + + // We add NodeIds to 'krate.proc_macros' in the order + // that we generate expressions. The position of each NodeId + // in the 'proc_macros' Vec corresponds to its position + // in the static array that will be generated let decls = { let local_path = |sp: Span, name| cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![name])); @@ -385,19 +403,26 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P { macros .iter() .map(|m| match m { - ProcMacro::Derive(cd) => cx.expr_call( - span, - proc_macro_ty_method_path(custom_derive), - vec![ - cx.expr_str(cd.span, cd.trait_name), - cx.expr_vec_slice( - span, - cd.attrs.iter().map(|&s| cx.expr_str(cd.span, s)).collect::>(), - ), - local_path(cd.span, cd.function_name), - ], - ), + ProcMacro::Derive(cd) => { + krate_ref.borrow_mut().proc_macros.push(cd.id); + cx.expr_call( + span, + proc_macro_ty_method_path(custom_derive), + vec![ + cx.expr_str(cd.span, cd.trait_name), + cx.expr_vec_slice( + span, + cd.attrs + .iter() + .map(|&s| cx.expr_str(cd.span, s)) + .collect::>(), + ), + local_path(cd.span, cd.function_name), + ], + ) + } ProcMacro::Def(ca) => { + krate_ref.borrow_mut().proc_macros.push(ca.id); let ident = match ca.def_type { ProcMacroDefType::Attr => attr, ProcMacroDefType::Bang => bang, diff --git a/src/librustc_builtin_macros/source_util.rs b/src/librustc_builtin_macros/source_util.rs index 264223bafbc..662bbe6a287 100644 --- a/src/librustc_builtin_macros/source_util.rs +++ b/src/librustc_builtin_macros/source_util.rs @@ -1,14 +1,14 @@ +use rustc_ast::ast; +use rustc_ast::ptr::P; +use rustc_ast::token; +use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; use rustc_expand::base::{self, *}; use rustc_expand::panictry; -use rustc_parse::{self, new_sub_parser_from_file, parser::Parser, DirectoryOwnership}; +use rustc_parse::{self, new_sub_parser_from_file, parser::Parser}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_span::symbol::Symbol; use rustc_span::{self, Pos, Span}; -use syntax::ast; -use syntax::ptr::P; -use syntax::token; -use syntax::tokenstream::TokenStream; use smallvec::SmallVec; @@ -108,8 +108,7 @@ pub fn expand_include<'cx>( return DummyResult::any(sp); } }; - let directory_ownership = DirectoryOwnership::Owned { relative: None }; - let p = new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp); + let p = new_sub_parser_from_file(cx.parse_sess(), &file, None, sp); struct ExpandResult<'a> { p: Parser<'a>, diff --git a/src/librustc_builtin_macros/standard_library_imports.rs b/src/librustc_builtin_macros/standard_library_imports.rs index 6663eecbf5f..f48fd6df9c9 100644 --- a/src/librustc_builtin_macros/standard_library_imports.rs +++ b/src/librustc_builtin_macros/standard_library_imports.rs @@ -1,3 +1,5 @@ +use rustc_ast::ptr::P; +use rustc_ast::{ast, attr}; use rustc_expand::base::{ExtCtxt, Resolver}; use rustc_expand::expand::ExpansionConfig; use rustc_session::parse::ParseSess; @@ -5,8 +7,6 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::AstPass; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::DUMMY_SP; -use syntax::ptr::P; -use syntax::{ast, attr}; pub fn inject( mut krate: ast::Crate, @@ -39,7 +39,7 @@ pub fn inject( let call_site = DUMMY_SP.with_call_site_ctxt(expn_id); let ecfg = ExpansionConfig::default("std_lib_injection".to_string()); - let cx = ExtCtxt::new(sess, ecfg, resolver); + let cx = ExtCtxt::new(sess, ecfg, resolver, None); // .rev() to preserve ordering above in combination with insert(0, ...) for &name in names.iter().rev() { diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs index 02a0bc00c11..39009ca27f1 100644 --- a/src/librustc_builtin_macros/test.rs +++ b/src/librustc_builtin_macros/test.rs @@ -2,13 +2,13 @@ /// Ideally, this code would be in libtest but for efficiency and error messages it lives here. use crate::util::check_builtin_macro_attribute; +use rustc_ast::ast; +use rustc_ast::attr; use rustc_ast_pretty::pprust; use rustc_expand::base::*; use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -use syntax::ast; -use syntax::attr; use std::iter; @@ -86,7 +86,7 @@ pub fn expand_test_or_bench( .raise(); }; - if let ast::ItemKind::Mac(_) = item.kind { + if let ast::ItemKind::MacCall(_) = item.kind { cx.parse_sess.span_diagnostic.span_warn( item.span, "`#[test]` attribute should not be used on macros. Use `#[cfg(test)]` instead.", @@ -184,83 +184,88 @@ pub fn expand_test_or_bench( ], // const $ident: test::TestDescAndFn = ast::ItemKind::Const( + ast::Defaultness::Final, cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), // test::TestDescAndFn { - cx.expr_struct( - sp, - test_path("TestDescAndFn"), - vec![ - // desc: test::TestDesc { - field( - "desc", - cx.expr_struct( - sp, - test_path("TestDesc"), - vec![ - // name: "path::to::test" - field( - "name", - cx.expr_call( - sp, - cx.expr_path(test_path("StaticTestName")), - vec![cx.expr_str( - sp, - Symbol::intern(&item_path( - // skip the name of the root module - &cx.current_expansion.module.mod_path[1..], - &item.ident, - )), - )], - ), - ), - // ignore: true | false - field("ignore", cx.expr_bool(sp, should_ignore(&item))), - // allow_fail: true | false - field("allow_fail", cx.expr_bool(sp, should_fail(&item))), - // should_panic: ... - field( - "should_panic", - match should_panic(cx, &item) { - // test::ShouldPanic::No - ShouldPanic::No => cx.expr_path(should_panic_path("No")), - // test::ShouldPanic::Yes - ShouldPanic::Yes(None) => { - cx.expr_path(should_panic_path("Yes")) - } - // test::ShouldPanic::YesWithMessage("...") - ShouldPanic::Yes(Some(sym)) => cx.expr_call( + Some( + cx.expr_struct( + sp, + test_path("TestDescAndFn"), + vec![ + // desc: test::TestDesc { + field( + "desc", + cx.expr_struct( + sp, + test_path("TestDesc"), + vec![ + // name: "path::to::test" + field( + "name", + cx.expr_call( sp, - cx.expr_path(should_panic_path("YesWithMessage")), - vec![cx.expr_str(sp, sym)], + cx.expr_path(test_path("StaticTestName")), + vec![cx.expr_str( + sp, + Symbol::intern(&item_path( + // skip the name of the root module + &cx.current_expansion.module.mod_path[1..], + &item.ident, + )), + )], ), - }, - ), - // test_type: ... - field( - "test_type", - match test_type(cx) { - // test::TestType::UnitTest - TestType::UnitTest => { - cx.expr_path(test_type_path("UnitTest")) - } - // test::TestType::IntegrationTest - TestType::IntegrationTest => { - cx.expr_path(test_type_path("IntegrationTest")) - } - // test::TestPath::Unknown - TestType::Unknown => { - cx.expr_path(test_type_path("Unknown")) - } - }, - ), - // }, - ], + ), + // ignore: true | false + field("ignore", cx.expr_bool(sp, should_ignore(&item))), + // allow_fail: true | false + field("allow_fail", cx.expr_bool(sp, should_fail(&item))), + // should_panic: ... + field( + "should_panic", + match should_panic(cx, &item) { + // test::ShouldPanic::No + ShouldPanic::No => { + cx.expr_path(should_panic_path("No")) + } + // test::ShouldPanic::Yes + ShouldPanic::Yes(None) => { + cx.expr_path(should_panic_path("Yes")) + } + // test::ShouldPanic::YesWithMessage("...") + ShouldPanic::Yes(Some(sym)) => cx.expr_call( + sp, + cx.expr_path(should_panic_path("YesWithMessage")), + vec![cx.expr_str(sp, sym)], + ), + }, + ), + // test_type: ... + field( + "test_type", + match test_type(cx) { + // test::TestType::UnitTest + TestType::UnitTest => { + cx.expr_path(test_type_path("UnitTest")) + } + // test::TestType::IntegrationTest + TestType::IntegrationTest => { + cx.expr_path(test_type_path("IntegrationTest")) + } + // test::TestPath::Unknown + TestType::Unknown => { + cx.expr_path(test_type_path("Unknown")) + } + }, + ), + // }, + ], + ), ), - ), - // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) - field("testfn", test_fn), // } - ], - ), // } + // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) + field("testfn", test_fn), // } + ], + ), // } + ), ), ); test_const = test_const.map(|mut tc| { @@ -308,7 +313,7 @@ fn should_fail(i: &ast::Item) -> bool { fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { match attr::find_by_name(&i.attrs, sym::should_panic) { Some(attr) => { - let ref sd = cx.parse_sess.span_diagnostic; + let sd = &cx.parse_sess.span_diagnostic; match attr.meta_item_list() { // Handle #[should_panic(expected = "foo")] @@ -373,8 +378,8 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType { fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic); - let ref sd = cx.parse_sess.span_diagnostic; - if let ast::ItemKind::Fn(ref sig, ref generics, _) = i.kind { + let sd = &cx.parse_sess.span_diagnostic; + if let ast::ItemKind::Fn(_, ref sig, ref generics, _) = i.kind { if let ast::Unsafe::Yes(span) = sig.header.unsafety { sd.struct_span_err(i.span, "unsafe functions cannot be used for tests") .span_label(span, "`unsafe` because of this") @@ -391,8 +396,8 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { // If the termination trait is active, the compiler will check that the output // type implements the `Termination` trait as `libtest` enforces that. let has_output = match sig.decl.output { - ast::FunctionRetTy::Default(..) => false, - ast::FunctionRetTy::Ty(ref t) if t.kind.is_unit() => false, + ast::FnRetTy::Default(..) => false, + ast::FnRetTy::Ty(ref t) if t.kind.is_unit() => false, _ => true, }; @@ -423,7 +428,7 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { } fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { - let has_sig = if let ast::ItemKind::Fn(ref sig, _, _) = i.kind { + let has_sig = if let ast::ItemKind::Fn(_, ref sig, _, _) = i.kind { // N.B., inadequate check, but we're running // well before resolve, can't get too deep. sig.decl.inputs.len() == 1 diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs index 70f1c0e4e2d..b87767f4a41 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/src/librustc_builtin_macros/test_harness.rs @@ -1,6 +1,11 @@ // Code that generates a test runner to run all the tests in a crate use log::debug; +use rustc_ast::ast::{self, Ident}; +use rustc_ast::attr; +use rustc_ast::entry::{self, EntryPointType}; +use rustc_ast::mut_visit::{ExpectOne, *}; +use rustc_ast::ptr::P; use rustc_expand::base::{ExtCtxt, Resolver}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; @@ -11,11 +16,6 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::PanicStrategy; use smallvec::{smallvec, SmallVec}; -use syntax::ast::{self, Ident}; -use syntax::attr; -use syntax::entry::{self, EntryPointType}; -use syntax::mut_visit::{ExpectOne, *}; -use syntax::ptr::P; use std::{iter, mem}; @@ -138,7 +138,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { smallvec![P(item)] } - fn visit_mac(&mut self, _mac: &mut ast::Mac) { + fn visit_mac(&mut self, _mac: &mut ast::MacCall) { // Do nothing. } } @@ -170,22 +170,13 @@ impl MutVisitor for EntryPointCleaner { )); let allow_dead_code_item = attr::mk_list_item(allow_ident, vec![dc_nested]); let allow_dead_code = attr::mk_attr_outer(allow_dead_code_item); + let attrs = attrs + .into_iter() + .filter(|attr| !attr.check_name(sym::main) && !attr.check_name(sym::start)) + .chain(iter::once(allow_dead_code)) + .collect(); - ast::Item { - id, - ident, - attrs: attrs - .into_iter() - .filter(|attr| { - !attr.check_name(sym::main) && !attr.check_name(sym::start) - }) - .chain(iter::once(allow_dead_code)) - .collect(), - kind, - vis, - span, - tokens, - } + ast::Item { id, ident, attrs, kind, vis, span, tokens } }), EntryPointType::None | EntryPointType::OtherMain => item, }; @@ -193,7 +184,7 @@ impl MutVisitor for EntryPointCleaner { smallvec![item] } - fn visit_mac(&mut self, _mac: &mut ast::Mac) { + fn visit_mac(&mut self, _mac: &mut ast::MacCall) { // Do nothing. } } @@ -211,7 +202,7 @@ fn generate_test_harness( let mut econfig = ExpansionConfig::default("test".to_string()); econfig.features = Some(features); - let ext_cx = ExtCtxt::new(sess, econfig, resolver); + let ext_cx = ExtCtxt::new(sess, econfig, resolver, None); let expn_id = ext_cx.resolver.expansion_for_ast_pass( DUMMY_SP, @@ -305,9 +296,10 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { ecx.block(sp, vec![call_test_main]) }; - let decl = ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)); + let decl = ecx.fn_decl(vec![], ast::FnRetTy::Ty(main_ret_ty)); let sig = ast::FnSig { decl, header: ast::FnHeader::default() }; - let main = ast::ItemKind::Fn(sig, ast::Generics::default(), Some(main_body)); + let def = ast::Defaultness::Final; + let main = ast::ItemKind::Fn(def, sig, ast::Generics::default(), Some(main_body)); // Honor the reexport_test_harness_main attribute let main_id = match cx.reexport_test_harness_main { @@ -334,7 +326,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { /// &[&test1, &test2] fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P { debug!("building test vector from {} tests", cx.test_cases.len()); - let ref ecx = cx.ext_cx; + let ecx = &cx.ext_cx; ecx.expr_vec_slice( sp, diff --git a/src/librustc_builtin_macros/trace_macros.rs b/src/librustc_builtin_macros/trace_macros.rs index c0b373f1370..c17f2afe494 100644 --- a/src/librustc_builtin_macros/trace_macros.rs +++ b/src/librustc_builtin_macros/trace_macros.rs @@ -1,7 +1,7 @@ +use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_expand::base::{self, ExtCtxt}; use rustc_span::symbol::kw; use rustc_span::Span; -use syntax::tokenstream::{TokenStream, TokenTree}; pub fn expand_trace_macros( cx: &mut ExtCtxt<'_>, diff --git a/src/librustc_builtin_macros/util.rs b/src/librustc_builtin_macros/util.rs index b7d1a5d1d7c..b486eadd1a8 100644 --- a/src/librustc_builtin_macros/util.rs +++ b/src/librustc_builtin_macros/util.rs @@ -1,12 +1,12 @@ +use rustc_ast::ast::MetaItem; use rustc_expand::base::ExtCtxt; use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; use rustc_span::Symbol; -use syntax::ast::MetaItem; pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) { // All the built-in macro attributes are "words" at the moment. - let template = AttributeTemplate::only_word(); + let template = AttributeTemplate { word: true, ..Default::default() }; let attr = ecx.attribute(meta_item.clone()); validate_attr::check_builtin_attribute(ecx.parse_sess, &attr, name, template); } diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml index 73bb4daed23..76f0a778988 100644 --- a/src/librustc_codegen_llvm/Cargo.toml +++ b/src/librustc_codegen_llvm/Cargo.toml @@ -14,6 +14,7 @@ doctest = false bitflags = "1.0" flate2 = "1.0" libc = "0.2" +measureme = "0.7.1" log = "0.4" rustc = { path = "../librustc" } rustc-demangle = "0.1" @@ -32,6 +33,6 @@ rustc_session = { path = "../librustc_session" } rustc_serialize = { path = "../libserialize", package = "serialize" } rustc_target = { path = "../librustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } ykpack = { git = "https://github.com/softdevteam/yk" } diff --git a/src/librustc_codegen_llvm/README.md b/src/librustc_codegen_llvm/README.md index dda2e5ac18f..97d8f76623e 100644 --- a/src/librustc_codegen_llvm/README.md +++ b/src/librustc_codegen_llvm/README.md @@ -2,6 +2,6 @@ The `codegen` crate contains the code to convert from MIR into LLVM IR, and then from LLVM IR into machine code. In general it contains code that runs towards the end of the compilation process. -For more information about how codegen works, see the [rustc guide]. +For more information about how codegen works, see the [rustc dev guide]. -[rustc guide]: https://rust-lang.github.io/rustc-guide/codegen.html +[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/codegen.html diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index c79d9f77e65..470a2bb8e1e 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -148,7 +148,7 @@ impl LlvmType for CastTarget { .prefix .iter() .flat_map(|option_kind| { - option_kind.map(|kind| Reg { kind: kind, size: self.prefix_chunk }.llvm_type(cx)) + option_kind.map(|kind| Reg { kind, size: self.prefix_chunk }.llvm_type(cx)) }) .chain((0..rest_count).map(|_| rest_ll_unit)) .collect(); diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs index 6dcf49f23fe..4e7bc9fa0e2 100644 --- a/src/librustc_codegen_llvm/allocator.rs +++ b/src/librustc_codegen_llvm/allocator.rs @@ -1,10 +1,8 @@ -use std::ffi::CString; - use crate::attributes; use libc::c_uint; use rustc::bug; use rustc::ty::TyCtxt; -use syntax::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; +use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; use crate::llvm::{self, False, True}; use crate::ModuleLlvm; @@ -50,8 +48,8 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: Alloc args.len() as c_uint, False, ); - let name = CString::new(format!("__rust_{}", method.name)).unwrap(); - let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr(), ty); + let name = format!("__rust_{}", method.name); + let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty); if tcx.sess.target.target.options.default_hidden_visibility { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); @@ -60,8 +58,9 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: Alloc attributes::emit_uwtable(llfn, true); } - let callee = CString::new(kind.fn_name(method.name)).unwrap(); - let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr(), ty); + let callee = kind.fn_name(method.name); + let callee = + llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty); llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden); let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast()); @@ -73,14 +72,8 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: Alloc .enumerate() .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint)) .collect::>(); - let ret = llvm::LLVMRustBuildCall( - llbuilder, - callee, - args.as_ptr(), - args.len() as c_uint, - None, - "\0".as_ptr().cast(), - ); + let ret = + llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None); llvm::LLVMSetTailCall(ret, True); if output.is_some() { llvm::LLVMBuildRet(llbuilder, ret); diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs index e816bdeb1c9..6edc3d5ecd4 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/src/librustc_codegen_llvm/asm.rs @@ -12,7 +12,6 @@ use rustc_span::Span; use libc::{c_char, c_uint}; use log::debug; -use std::ffi::{CStr, CString}; impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { fn codegen_inline_asm( @@ -29,11 +28,17 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { let mut indirect_outputs = vec![]; for (i, (out, &place)) in ia.outputs.iter().zip(&outputs).enumerate() { if out.is_rw { - inputs.push(self.load_operand(place).immediate()); + let operand = self.load_operand(place); + if let OperandValue::Immediate(_) = operand.val { + inputs.push(operand.immediate()); + } ext_constraints.push(i.to_string()); } if out.is_indirect { - indirect_outputs.push(self.load_operand(place).immediate()); + let operand = self.load_operand(place); + if let OperandValue::Immediate(_) = operand.val { + indirect_outputs.push(operand.immediate()); + } } else { output_types.push(place.layout.llvm_type(self.cx())); } @@ -60,7 +65,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { .chain(ia.inputs.iter().map(|s| s.to_string())) .chain(ext_constraints) .chain(clobbers) - .chain(arch_clobbers.iter().map(|s| s.to_string())) + .chain(arch_clobbers.iter().map(|s| (*s).to_string())) .collect::>() .join(","); @@ -74,12 +79,11 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { _ => self.type_struct(&output_types, false), }; - let asm = CString::new(ia.asm.as_str().as_bytes()).unwrap(); - let constraint_cstr = CString::new(all_constraints).unwrap(); + let asm = ia.asm.as_str(); let r = inline_asm_call( self, &asm, - &constraint_cstr, + &all_constraints, &inputs, output_type, ia.volatile, @@ -119,22 +123,22 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { impl AsmMethods for CodegenCx<'ll, 'tcx> { fn codegen_global_asm(&self, ga: &hir::GlobalAsm) { - let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap(); + let asm = ga.asm.as_str(); unsafe { - llvm::LLVMRustAppendModuleInlineAsm(self.llmod, asm.as_ptr()); + llvm::LLVMRustAppendModuleInlineAsm(self.llmod, asm.as_ptr().cast(), asm.len()); } } } fn inline_asm_call( bx: &mut Builder<'a, 'll, 'tcx>, - asm: &CStr, - cons: &CStr, + asm: &str, + cons: &str, inputs: &[&'ll Value], output: &'ll llvm::Type, volatile: bool, alignstack: bool, - dia: ::syntax::ast::AsmDialect, + dia: ::rustc_ast::ast::AsmDialect, ) -> Option<&'ll Value> { let volatile = if volatile { llvm::True } else { llvm::False }; let alignstack = if alignstack { llvm::True } else { llvm::False }; @@ -151,13 +155,15 @@ fn inline_asm_call( let fty = bx.cx.type_func(&argtys[..], output); unsafe { // Ask LLVM to verify that the constraints are well-formed. - let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr()); + let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len()); debug!("constraint verification result: {:?}", constraints_ok); if constraints_ok { let v = llvm::LLVMRustInlineAsm( fty, - asm.as_ptr(), - cons.as_ptr(), + asm.as_ptr().cast(), + asm.len(), + cons.as_ptr().cast(), + cons.len(), volatile, alignstack, llvm::AsmDialect::from_generic(dia), diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index a9e4fdba030..072607fff85 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -3,8 +3,6 @@ use std::ffi::CString; use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc::session::config::{OptLevel, Sanitizer}; -use rustc::session::Session; use rustc::ty::layout::HasTyCtxt; use rustc::ty::query::Providers; use rustc::ty::{self, Ty, TyCtxt}; @@ -13,6 +11,8 @@ use rustc_data_structures::const_cstr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_session::config::{OptLevel, Sanitizer}; +use rustc_session::Session; use rustc_target::abi::call::Conv; use rustc_target::spec::PanicStrategy; diff --git a/src/librustc_codegen_llvm/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs index 455b7086212..239ca57ba41 100644 --- a/src/librustc_codegen_llvm/back/archive.rs +++ b/src/librustc_codegen_llvm/back/archive.rs @@ -9,9 +9,9 @@ use std::str; use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind}; -use rustc::session::Session; use rustc_codegen_ssa::back::archive::{find_library, ArchiveBuilder}; use rustc_codegen_ssa::{looks_like_rust_object_file, METADATA_FILENAME, RLIB_BYTECODE_EXTENSION}; +use rustc_session::Session; use rustc_span::symbol::Symbol; struct ArchiveConfig<'a> { diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index e3d69fc5c76..1b64750f51f 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -9,7 +9,6 @@ use log::{debug, info}; use rustc::bug; use rustc::dep_graph::WorkProduct; use rustc::middle::exported_symbols::SymbolExportLevel; -use rustc::session::config::{self, Lto}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; @@ -19,6 +18,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{FatalError, Handler}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_session::cgu_reuse_tracker::CguReuse; +use rustc_session::config::{self, Lto}; use std::ffi::{CStr, CString}; use std::fs::File; @@ -237,7 +237,7 @@ fn fat_lto( let module: ModuleCodegen = match costliest_module { Some((_cost, i)) => in_memory.remove(i), None => { - assert!(serialized_modules.len() > 0, "must have at least one serialized module"); + assert!(!serialized_modules.is_empty(), "must have at least one serialized module"); let (buffer, name) = serialized_modules.remove(0); info!("no in-memory regular modules to choose from, parsing {:?}", name); ModuleCodegen { @@ -504,7 +504,7 @@ fn thin_lto( // // This strategy means we can always save the computed imports as // canon: when we reuse the post-ThinLTO version, condition (3.) - // ensures that the curent import set is the same as the previous + // ensures that the current import set is the same as the previous // one. (And of course, when we don't reuse the post-ThinLTO // version, the current import set *is* the correct one, since we // are doing the ThinLTO in this current compilation cycle.) @@ -538,7 +538,7 @@ fn thin_lto( })); } - // Save the curent ThinLTO import information for the next compilation + // Save the current ThinLTO import information for the next compilation // session, overwriting the previous serialized imports (if any). if let Some(path) = import_map_path { if let Err(err) = curr_import_map.save_to_file(&path) { @@ -593,7 +593,7 @@ pub(crate) fn run_pass_manager( } else { opt_level }; - write::optimize_with_new_llvm_pass_manager(module, config, opt_level, opt_stage); + write::optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage); debug!("lto done"); return; } @@ -917,7 +917,7 @@ impl ThinLTOImports { if line.is_empty() { let importing_module = current_module.take().expect("Importing module not set"); imports.insert(importing_module, mem::replace(&mut current_imports, vec![])); - } else if line.starts_with(" ") { + } else if line.starts_with(' ') { // Space marks an imported module assert_ne!(current_module, None); current_imports.push(line.trim().to_string()); diff --git a/src/librustc_codegen_llvm/back/profiling.rs b/src/librustc_codegen_llvm/back/profiling.rs new file mode 100644 index 00000000000..2741f7d848e --- /dev/null +++ b/src/librustc_codegen_llvm/back/profiling.rs @@ -0,0 +1,58 @@ +use measureme::{event_id::SEPARATOR_BYTE, EventId, StringComponent, StringId}; +use rustc_data_structures::profiling::{SelfProfiler, TimingGuard}; +use std::ffi::{c_void, CStr}; +use std::os::raw::c_char; +use std::sync::Arc; + +fn llvm_args_to_string_id(profiler: &SelfProfiler, pass_name: &str, ir_name: &str) -> EventId { + let pass_name = profiler.get_or_alloc_cached_string(pass_name); + let mut components = vec![StringComponent::Ref(pass_name)]; + // handle that LazyCallGraph::SCC is a comma separated list within parentheses + let parentheses: &[_] = &['(', ')']; + let trimmed = ir_name.trim_matches(parentheses); + for part in trimmed.split(", ") { + let demangled_ir_name = rustc_demangle::demangle(part).to_string(); + let ir_name = profiler.get_or_alloc_cached_string(demangled_ir_name); + components.push(StringComponent::Value(SEPARATOR_BYTE)); + components.push(StringComponent::Ref(ir_name)); + } + EventId::from_label(profiler.alloc_string(components.as_slice())) +} + +pub struct LlvmSelfProfiler<'a> { + profiler: Arc, + stack: Vec>, + llvm_pass_event_kind: StringId, +} + +impl<'a> LlvmSelfProfiler<'a> { + pub fn new(profiler: Arc) -> Self { + let llvm_pass_event_kind = profiler.alloc_string("LLVM Pass"); + Self { profiler, stack: Vec::default(), llvm_pass_event_kind } + } + + fn before_pass_callback(&'a mut self, pass_name: &str, ir_name: &str) { + let event_id = llvm_args_to_string_id(&self.profiler, pass_name, ir_name); + + self.stack.push(TimingGuard::start(&self.profiler, self.llvm_pass_event_kind, event_id)); + } + fn after_pass_callback(&mut self) { + self.stack.pop(); + } +} + +pub unsafe extern "C" fn selfprofile_before_pass_callback( + llvm_self_profiler: *mut c_void, + pass_name: *const c_char, + ir_name: *const c_char, +) { + let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>); + let pass_name = CStr::from_ptr(pass_name).to_str().expect("valid UTF-8"); + let ir_name = CStr::from_ptr(ir_name).to_str().expect("valid UTF-8"); + llvm_self_profiler.before_pass_callback(pass_name, ir_name); +} + +pub unsafe extern "C" fn selfprofile_after_pass_callback(llvm_self_profiler: *mut c_void) { + let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>); + llvm_self_profiler.after_pass_callback(); +} diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 9008970847a..2327b96e26c 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -1,6 +1,9 @@ use crate::attributes; use crate::back::bytecode; use crate::back::lto::ThinBuffer; +use crate::back::profiling::{ + selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler, +}; use crate::base; use crate::common; use crate::consts; @@ -12,8 +15,6 @@ use crate::LlvmCodegenBackend; use crate::ModuleLlvm; use log::debug; use rustc::bug; -use rustc::session::config::{self, Lto, OutputType, Passes, Sanitizer, SwitchWithOptPath}; -use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_codegen_ssa::back::write::{run_assembler, CodegenContext, ModuleConfig}; use rustc_codegen_ssa::traits::*; @@ -22,6 +23,8 @@ use rustc_data_structures::small_c_str::SmallCStr; use rustc_errors::{FatalError, Handler}; use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_hir::def_id::LOCAL_CRATE; +use rustc_session::config::{self, Lto, OutputType, Passes, Sanitizer, SwitchWithOptPath}; +use rustc_session::Session; use libc::{c_char, c_int, c_uint, c_void, size_t}; use std::ffi::CString; @@ -348,6 +351,7 @@ pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool { } pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( + cgcx: &CodegenContext, module: &ModuleCodegen, config: &ModuleConfig, opt_level: config::OptLevel, @@ -372,6 +376,13 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( None }; + let llvm_selfprofiler = if cgcx.prof.llvm_recording_enabled() { + let mut llvm_profiler = LlvmSelfProfiler::new(cgcx.prof.get_self_profiler().unwrap()); + &mut llvm_profiler as *mut _ as *mut c_void + } else { + std::ptr::null_mut() + }; + // FIXME: NewPM doesn't provide a facility to pass custom InlineParams. // We would have to add upstream support for this first, before we can support // config.inline_threshold and our more aggressive default thresholds. @@ -394,6 +405,9 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( sanitizer_options.as_ref(), pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + llvm_selfprofiler, + selfprofile_before_pass_callback, + selfprofile_after_pass_callback, ); } @@ -428,10 +442,15 @@ pub(crate) unsafe fn optimize( _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO, _ => llvm::OptStage::PreLinkNoLTO, }; - optimize_with_new_llvm_pass_manager(module, config, opt_level, opt_stage); + optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage); return Ok(()); } + if cgcx.prof.llvm_recording_enabled() { + diag_handler + .warn("`-Z self-profile-events = llvm` requires `-Z new-llvm-pass-manager`"); + } + // Create the two optimizing pass managers. These mirror what clang // does, and are by populated by LLVM's default PassManagerBuilder. // Each manager has a different set of passes, but they also share @@ -706,7 +725,7 @@ pub(crate) unsafe fn codegen( Err(_) => return 0, }; - if let Err(_) = write!(cursor, "{:#}", demangled) { + if write!(cursor, "{:#}", demangled).is_err() { // Possible only if provided buffer is not big enough return 0; } diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index f5be2ed0035..f74c16dee3a 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -28,13 +28,13 @@ use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc::middle::cstore::EncodedMetadata; use rustc::middle::exported_symbols; use rustc::mir::mono::{Linkage, Visibility}; -use rustc::session::config::DebugInfo; use rustc::ty::TyCtxt; use rustc_codegen_ssa::base::maybe_create_entry_wrapper; use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_data_structures::small_c_str::SmallCStr; +use rustc_session::config::DebugInfo; use rustc_span::symbol::Symbol; use std::ffi::CString; diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index 9cc9486949f..c84b3cc287a 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -7,7 +7,6 @@ use crate::type_of::LayoutLlvmExt; use crate::value::Value; use libc::{c_char, c_uint}; use log::debug; -use rustc::session::config::{self, Sanitizer}; use rustc::ty::layout::{self, Align, Size, TyLayout}; use rustc::ty::{self, Instance, SymbolName, Ty, TyCtxt}; use rustc_codegen_ssa::base::to_immediate; @@ -19,6 +18,7 @@ use rustc_codegen_ssa::MemFlags; use rustc_data_structures::const_cstr; use rustc_data_structures::small_c_str::SmallCStr; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_session::config::{self, Sanitizer}; use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; use std::ffi::{CStr, CString}; @@ -362,8 +362,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { rhs: Self::Value, ) -> (Self::Value, Self::Value) { use rustc::ty::{Int, Uint}; - use syntax::ast::IntTy::*; - use syntax::ast::UintTy::*; + use rustc_ast::ast::IntTy::*; + use rustc_ast::ast::UintTy::*; let new_kind = match ty.kind { Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.ptr_width)), @@ -1075,7 +1075,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { args.as_ptr() as *const &llvm::Value, args.len() as c_uint, bundle, - UNNAMED, ) } } diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index 1d6bfb32159..609ddfc1d3a 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -18,8 +18,8 @@ use rustc_codegen_ssa::mir::place::PlaceRef; use libc::{c_char, c_uint}; +use rustc_ast::ast::Mutability; use rustc_span::symbol::Symbol; -use syntax::ast::Mutability; pub use crate::context::CodegenCx; @@ -259,11 +259,14 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { let base_addr = match alloc_kind { Some(GlobalAlloc::Memory(alloc)) => { let init = const_alloc_to_llvm(self, alloc); - if alloc.mutability == Mutability::Mut { - self.static_addr_of_mut(init, alloc.align, None) - } else { - self.static_addr_of(init, alloc.align, None) + let value = match alloc.mutability { + Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), + _ => self.static_addr_of(init, alloc.align, None), + }; + if !self.sess().fewer_names() { + llvm::set_value_name(value, format!("{:?}", ptr.alloc_id).as_bytes()); } + value } Some(GlobalAlloc::Function(fn_instance)) => self.get_fn_addr(fn_instance), Some(GlobalAlloc::Static(def_id)) => { @@ -320,7 +323,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } -pub fn val_ty(v: &'ll Value) -> &'ll Type { +pub fn val_ty(v: &Value) -> &Type { unsafe { llvm::LLVMTypeOf(v) } } @@ -342,6 +345,6 @@ fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 { ((hi as u128) << 64) | (lo as u128) } -fn try_as_const_integral(v: &'ll Value) -> Option<&'ll ConstantInt> { +fn try_as_const_integral(v: &Value) -> Option<&ConstantInt> { unsafe { llvm::LLVMIsAConstantInt(v) } } diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index 38090cb26bc..09a84aff168 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -78,11 +78,9 @@ pub fn codegen_static_initializer( cx: &CodegenCx<'ll, 'tcx>, def_id: DefId, ) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> { - let static_ = cx.tcx.const_eval_poly(def_id)?; - - let alloc = match static_.val { - ty::ConstKind::Value(ConstValue::ByRef { alloc, offset }) if offset.bytes() == 0 => alloc, - _ => bug!("static const eval returned {:#?}", static_), + let alloc = match cx.tcx.const_eval_poly(def_id)? { + ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => alloc, + val => bug!("static const eval returned {:#?}", val), }; Ok((const_alloc_to_llvm(cx, alloc), alloc)) } diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index acbcc50a678..b574c711693 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -1,38 +1,33 @@ -use crate::abi::FnAbi; use crate::attributes; +use crate::callee::get_fn; use crate::debuginfo; use crate::llvm; use crate::llvm_util; -use crate::value::Value; -use rustc::dep_graph::DepGraphSafe; - use crate::type_::Type; -use rustc_codegen_ssa::traits::*; +use crate::value::Value; -use crate::callee::get_fn; use rustc::bug; +use rustc::dep_graph::DepGraphSafe; use rustc::mir::mono::CodegenUnit; -use rustc::session::config::{self, CFGuard, DebugInfo}; -use rustc::session::Session; +use rustc::sir; use rustc::ty::layout::{ - FnAbiExt, HasParamEnv, LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx, + HasParamEnv, LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx, }; use rustc::ty::{self, Instance, Ty, TyCtxt}; use rustc_codegen_ssa::base::wants_msvc_seh; +use rustc_codegen_ssa::traits::*; use rustc_data_structures::base_n; use rustc_data_structures::const_cstr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_hir::Unsafety; -use rustc_target::spec::{HasTargetSpec, Target}; - -use crate::abi::Abi; -use rustc::sir; +use rustc_session::config::{self, CFGuard, DebugInfo}; +use rustc_session::Session; use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_span::symbol::Symbol; +use rustc_target::spec::{HasTargetSpec, Target}; + use std::cell::{Cell, RefCell}; use std::ffi::CStr; -use std::iter; use std::str; use std::sync::Arc; @@ -88,7 +83,6 @@ pub struct CodegenCx<'ll, 'tcx> { pub dbg_cx: Option>, eh_personality: Cell>, - eh_unwind_resume: Cell>, pub rust_try_fn: Cell>, intrinsics: RefCell>, @@ -177,7 +171,6 @@ pub unsafe fn create_module( let llvm_data_layout = llvm::LLVMGetDataLayout(llmod); let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes()) - .ok() .expect("got a non-UTF8 data-layout from LLVM"); // Unfortunately LLVM target specs change over time, and right now we @@ -336,7 +329,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { isize_ty, dbg_cx, eh_personality: Cell::new(None), - eh_unwind_resume: Cell::new(None), rust_try_fn: Cell::new(None), intrinsics: Default::default(), local_gen_sym_counter: Cell::new(0), @@ -415,45 +407,6 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { llfn } - // Returns a Value of the "eh_unwind_resume" lang item if one is defined, - // otherwise declares it as an external function. - fn eh_unwind_resume(&self) -> &'ll Value { - let unwresume = &self.eh_unwind_resume; - if let Some(llfn) = unwresume.get() { - return llfn; - } - - let tcx = self.tcx; - assert!(self.sess().target.target.options.custom_unwind_resume); - if let Some(def_id) = tcx.lang_items().eh_unwind_resume() { - let llfn = self.get_fn_addr( - ty::Instance::resolve( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - tcx.intern_substs(&[]), - ) - .unwrap(), - ); - unwresume.set(Some(llfn)); - return llfn; - } - - let sig = ty::Binder::bind(tcx.mk_fn_sig( - iter::once(tcx.mk_mut_ptr(tcx.types.u8)), - tcx.types.never, - false, - Unsafety::Unsafe, - Abi::C, - )); - - let fn_abi = FnAbi::of_fn_ptr(self, sig, &[]); - let llfn = self.declare_fn("rust_eh_unwind_resume", &fn_abi); - attributes::apply_target_cpu_attr(self, llfn); - unwresume.set(Some(llfn)); - llfn - } - fn sess(&self) -> &Session { &self.tcx.sess } diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index cdb9657e1ff..09422f4ec37 100644 --- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -1,5 +1,5 @@ -use super::metadata::file_metadata; -use super::utils::{span_start, DIB}; +use super::metadata::{file_metadata, UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER}; +use super::utils::DIB; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext}; use crate::common::CodegenCx; @@ -7,10 +7,6 @@ use crate::llvm; use crate::llvm::debuginfo::{DIScope, DISubprogram}; use rustc::mir::{Body, SourceScope}; -use libc::c_uint; - -use rustc_span::Pos; - use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; @@ -54,7 +50,7 @@ fn make_mir_scope( debug_context.scopes[parent] } else { // The root is the function itself. - let loc = span_start(cx, mir.span); + let loc = cx.lookup_debug_loc(mir.span.lo()); debug_context.scopes[scope] = DebugScope { scope_metadata: Some(fn_metadata), file_start_pos: loc.file.start_pos, @@ -70,7 +66,7 @@ fn make_mir_scope( return; } - let loc = span_start(cx, scope_data.span); + let loc = cx.lookup_debug_loc(scope_data.span.lo()); let file_metadata = file_metadata(cx, &loc.file.name, debug_context.defining_crate); let scope_metadata = unsafe { @@ -78,8 +74,8 @@ fn make_mir_scope( DIB(cx), parent_scope.scope_metadata.unwrap(), file_metadata, - loc.line as c_uint, - loc.col.to_usize() as c_uint, + loc.line.unwrap_or(UNKNOWN_LINE_NUMBER), + loc.col.unwrap_or(UNKNOWN_COLUMN_NUMBER), )) }; debug_context.scopes[scope] = DebugScope { diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs index eae461a575f..e4cbffb6db3 100644 --- a/src/librustc_codegen_llvm/debuginfo/gdb.rs +++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs @@ -6,11 +6,11 @@ use crate::builder::Builder; use crate::common::CodegenCx; use crate::value::Value; use rustc::bug; -use rustc::session::config::DebugInfo; use rustc_codegen_ssa::traits::*; +use rustc_session::config::DebugInfo; +use rustc_ast::attr; use rustc_span::symbol::sym; -use syntax::attr; /// Inserts a side-effect free instruction sequence that makes sure that the /// .debug_gdb_scripts global is referenced, so it isn't removed by the linker. diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index d1f70ad43bd..6a7ed4e1dc3 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -5,7 +5,7 @@ use self::RecursiveTypeDescription::*; use super::namespace::mangled_name_of_instance; use super::type_names::compute_debuginfo_type_name; use super::utils::{ - create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, span_start, DIB, + create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, DIB, }; use super::CrateDebugContext; @@ -24,7 +24,6 @@ use rustc::ich::NodeIdHashingMode; use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc::mir::interpret::truncate; use rustc::mir::{self, Field, GeneratorLayout}; -use rustc::session::config::{self, DebugInfo}; use rustc::ty::layout::{ self, Align, Integer, IntegerExt, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx, }; @@ -32,24 +31,23 @@ use rustc::ty::subst::{GenericArgKind, SubstsRef}; use rustc::ty::Instance; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; use rustc::{bug, span_bug}; +use rustc_ast::ast; use rustc_codegen_ssa::traits::*; use rustc_data_structures::const_cstr; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::small_c_str::SmallCStr; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_fs_util::path_to_c_string; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_index::vec::{Idx, IndexVec}; +use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::{Interner, Symbol}; use rustc_span::{self, FileName, Span}; use rustc_target::abi::HasDataLayout; -use syntax::ast; use libc::{c_longlong, c_uint}; use std::collections::hash_map::Entry; -use std::ffi::CString; use std::fmt::{self, Write}; use std::hash::{Hash, Hasher}; use std::iter; @@ -227,11 +225,11 @@ impl TypeMap<'ll, 'tcx> { /// Gets the unique type ID string for an enum variant part. /// Variant parts are not types and shouldn't really have their own ID, /// but it makes `set_members_of_composite_type()` simpler. - fn get_unique_type_id_str_of_enum_variant_part(&mut self, enum_type_id: UniqueTypeId) -> &str { - let variant_part_type_id = - format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id)); - let interner_key = self.unique_id_interner.intern(&variant_part_type_id); - self.unique_id_interner.get(interner_key) + fn get_unique_type_id_str_of_enum_variant_part( + &mut self, + enum_type_id: UniqueTypeId, + ) -> String { + format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id)) } } @@ -637,12 +635,14 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp unsafe { // The choice of type here is pretty arbitrary - // anything reading the debuginfo for a recursive - // type is going to see *somthing* weird - the only + // type is going to see *something* weird - the only // question is what exactly it will see. let (size, align) = cx.size_and_align_of(t); + let name = ""; llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), - SmallCStr::new("").as_ptr(), + name.as_ptr().cast(), + name.len(), size.bits(), align.bits() as u32, DW_ATE_unsigned, @@ -786,16 +786,17 @@ fn file_metadata_raw( let (file_name, directory) = v.key(); debug!("file_metadata: file_name: {:?}, directory: {:?}", file_name, directory); - let file_name = SmallCStr::new(if let Some(file_name) = file_name { - &file_name - } else { - "" - }); - let directory = - SmallCStr::new(if let Some(directory) = directory { &directory } else { "" }); + let file_name = file_name.as_deref().unwrap_or(""); + let directory = directory.as_deref().unwrap_or(""); let file_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateFile(DIB(cx), file_name.as_ptr(), directory.as_ptr()) + llvm::LLVMRustDIBuilderCreateFile( + DIB(cx), + file_name.as_ptr().cast(), + file_name.len(), + directory.as_ptr().cast(), + directory.len(), + ) }; v.insert(file_metadata); @@ -819,11 +820,11 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { }; let (size, align) = cx.size_and_align_of(t); - let name = SmallCStr::new(name); let ty_metadata = unsafe { llvm::LLVMRustDIBuilderCreateBasicType( DIB(cx), - name.as_ptr(), + name.as_ptr().cast(), + name.len(), size.bits(), align.bits() as u32, encoding, @@ -851,14 +852,15 @@ fn pointer_type_metadata( ) -> &'ll DIType { let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type); let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false); - let name = SmallCStr::new(&name); unsafe { llvm::LLVMRustDIBuilderCreatePointerType( DIB(cx), pointee_type_metadata, pointer_size.bits(), pointer_align.bits() as u32, - name.as_ptr(), + 0, // Ignore DWARF address space. + name.as_ptr().cast(), + name.len(), ) } } @@ -889,11 +891,9 @@ pub fn compile_unit_metadata( let producer = format!("clang LLVM ({})", rustc_producer); let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); - let name_in_debuginfo = SmallCStr::new(&name_in_debuginfo); - let work_dir = SmallCStr::new(&tcx.sess.working_dir.0.to_string_lossy()); - let producer = CString::new(producer).unwrap(); + let work_dir = tcx.sess.working_dir.0.to_string_lossy(); let flags = "\0"; - let split_name = "\0"; + let split_name = ""; // FIXME(#60020): // @@ -916,19 +916,23 @@ pub fn compile_unit_metadata( unsafe { let file_metadata = llvm::LLVMRustDIBuilderCreateFile( debug_context.builder, - name_in_debuginfo.as_ptr(), - work_dir.as_ptr(), + name_in_debuginfo.as_ptr().cast(), + name_in_debuginfo.len(), + work_dir.as_ptr().cast(), + work_dir.len(), ); let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( debug_context.builder, DW_LANG_RUST, file_metadata, - producer.as_ptr(), + producer.as_ptr().cast(), + producer.len(), tcx.sess.opts.optimize != config::OptLevel::No, flags.as_ptr().cast(), 0, split_name.as_ptr().cast(), + split_name.len(), kind, ); @@ -1021,12 +1025,12 @@ impl<'ll> MemberDescription<'ll> { cx: &CodegenCx<'ll, '_>, composite_type_metadata: &'ll DIScope, ) -> &'ll DIType { - let member_name = CString::new(self.name).unwrap(); unsafe { llvm::LLVMRustDIBuilderCreateVariantMemberType( DIB(cx), composite_type_metadata, - member_name.as_ptr(), + self.name.as_ptr().cast(), + self.name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, self.size.bits(), @@ -1779,13 +1783,20 @@ fn prepare_enum_metadata( .discriminants(cx.tcx) .zip(&def.variants) .map(|((_, discr), v)| { - let name = SmallCStr::new(&v.ident.as_str()); + let name = v.ident.as_str(); + let is_unsigned = match discr.ty.kind { + ty::Int(_) => false, + ty::Uint(_) => true, + _ => bug!("non integer discriminant"), + }; unsafe { Some(llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), - name.as_ptr(), + name.as_ptr().cast(), + name.len(), // FIXME: what if enumeration has i128 discriminant? - discr.val as u64, + discr.val as i64, + is_unsigned, )) } }) @@ -1794,13 +1805,15 @@ fn prepare_enum_metadata( .as_generator() .variant_range(enum_def_id, cx.tcx) .map(|variant_index| { - let name = SmallCStr::new(&substs.as_generator().variant_name(variant_index)); + let name = substs.as_generator().variant_name(variant_index); unsafe { Some(llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), - name.as_ptr(), - // FIXME: what if enumeration has i128 discriminant? - variant_index.as_usize() as u64, + name.as_ptr().cast(), + name.len(), + // Generators use u32 as discriminant type. + variant_index.as_u32().into(), + true, // IsUnsigned )) } }) @@ -1818,9 +1831,13 @@ fn prepare_enum_metadata( let discriminant_base_type_metadata = type_metadata(cx, discr.to_ty(cx.tcx), rustc_span::DUMMY_SP); + let item_name; let discriminant_name = match enum_type.kind { - ty::Adt(..) => SmallCStr::new(&cx.tcx.item_name(enum_def_id).as_str()), - ty::Generator(..) => SmallCStr::new(&enum_name), + ty::Adt(..) => { + item_name = cx.tcx.item_name(enum_def_id).as_str(); + &*item_name + } + ty::Generator(..) => enum_name.as_str(), _ => bug!(), }; @@ -1828,7 +1845,8 @@ fn prepare_enum_metadata( llvm::LLVMRustDIBuilderCreateEnumerationType( DIB(cx), containing_scope, - discriminant_name.as_ptr(), + discriminant_name.as_ptr().cast(), + discriminant_name.len(), file_metadata, UNKNOWN_LINE_NUMBER, discriminant_size.bits(), @@ -1863,11 +1881,6 @@ fn prepare_enum_metadata( _ => {} } - let enum_name = SmallCStr::new(&enum_name); - let unique_type_id_str = SmallCStr::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id), - ); - if use_enum_fallback(cx) { let discriminant_type_metadata = match layout.variants { layout::Variants::Single { .. } @@ -1882,20 +1895,27 @@ fn prepare_enum_metadata( } => Some(discriminant_type_metadata(discr.value)), }; - let enum_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateUnionType( - DIB(cx), - containing_scope, - enum_name.as_ptr(), - file_metadata, - UNKNOWN_LINE_NUMBER, - layout.size.bits(), - layout.align.abi.bits() as u32, - DIFlags::FlagZero, - None, - 0, // RuntimeLang - unique_type_id_str.as_ptr(), - ) + let enum_metadata = { + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id); + + unsafe { + llvm::LLVMRustDIBuilderCreateUnionType( + DIB(cx), + containing_scope, + enum_name.as_ptr().cast(), + enum_name.len(), + file_metadata, + UNKNOWN_LINE_NUMBER, + layout.size.bits(), + layout.align.abi.bits() as u32, + DIFlags::FlagZero, + None, + 0, // RuntimeLang + unique_type_id_str.as_ptr().cast(), + unique_type_id_str.len(), + ) + } }; return create_and_register_recursive_type_forward_declaration( @@ -1915,10 +1935,9 @@ fn prepare_enum_metadata( } let discriminator_name = match &enum_type.kind { - ty::Generator(..) => Some(SmallCStr::new(&"__state")), - _ => None, + ty::Generator(..) => "__state", + _ => "", }; - let discriminator_name = discriminator_name.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()); let discriminator_metadata = match layout.variants { // A single-variant enum has no discriminant. layout::Variants::Single { .. } => None, @@ -1946,7 +1965,8 @@ fn prepare_enum_metadata( Some(llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), containing_scope, - discriminator_name, + discriminator_name.as_ptr().cast(), + discriminator_name.len(), file_metadata, UNKNOWN_LINE_NUMBER, size.bits(), @@ -1972,7 +1992,8 @@ fn prepare_enum_metadata( Some(llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), containing_scope, - discriminator_name, + discriminator_name.as_ptr().cast(), + discriminator_name.len(), file_metadata, UNKNOWN_LINE_NUMBER, size.bits(), @@ -2001,18 +2022,18 @@ fn prepare_enum_metadata( } }; - let variant_part_unique_type_id_str = SmallCStr::new( - debug_context(cx) - .type_map - .borrow_mut() - .get_unique_type_id_str_of_enum_variant_part(unique_type_id), - ); + let variant_part_unique_type_id_str = debug_context(cx) + .type_map + .borrow_mut() + .get_unique_type_id_str_of_enum_variant_part(unique_type_id); let empty_array = create_DIArray(DIB(cx), &[]); + let name = ""; let variant_part = unsafe { llvm::LLVMRustDIBuilderCreateVariantPart( DIB(cx), containing_scope, - ptr::null_mut(), + name.as_ptr().cast(), + name.len(), file_metadata, UNKNOWN_LINE_NUMBER, layout.size.bits(), @@ -2020,29 +2041,38 @@ fn prepare_enum_metadata( DIFlags::FlagZero, discriminator_metadata, empty_array, - variant_part_unique_type_id_str.as_ptr(), + variant_part_unique_type_id_str.as_ptr().cast(), + variant_part_unique_type_id_str.len(), ) }; outer_fields.push(Some(variant_part)); - // The variant part must be wrapped in a struct according to DWARF. - let type_array = create_DIArray(DIB(cx), &outer_fields); - let struct_wrapper = unsafe { - llvm::LLVMRustDIBuilderCreateStructType( - DIB(cx), - Some(containing_scope), - enum_name.as_ptr(), - file_metadata, - UNKNOWN_LINE_NUMBER, - layout.size.bits(), - layout.align.abi.bits() as u32, - DIFlags::FlagZero, - None, - type_array, - 0, - None, - unique_type_id_str.as_ptr(), - ) + let struct_wrapper = { + // The variant part must be wrapped in a struct according to DWARF. + let type_array = create_DIArray(DIB(cx), &outer_fields); + + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id); + + unsafe { + llvm::LLVMRustDIBuilderCreateStructType( + DIB(cx), + Some(containing_scope), + enum_name.as_ptr().cast(), + enum_name.len(), + file_metadata, + UNKNOWN_LINE_NUMBER, + layout.size.bits(), + layout.align.abi.bits() as u32, + DIFlags::FlagZero, + None, + type_array, + 0, + None, + unique_type_id_str.as_ptr().cast(), + unique_type_id_str.len(), + ) + } }; return create_and_register_recursive_type_forward_declaration( @@ -2135,7 +2165,7 @@ fn set_members_of_composite_type( /// Computes the type parameters for a type, if any, for the given metadata. fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&'ll DIArray> { if let ty::Adt(def, substs) = ty.kind { - if !substs.types().next().is_none() { + if substs.types().next().is_some() { let generics = cx.tcx.generics_of(def.did); let names = get_parameter_names(cx, generics); let template_params: Vec<_> = substs @@ -2147,12 +2177,13 @@ fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&' cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_metadata(cx, actual_type, rustc_span::DUMMY_SP); - let name = SmallCStr::new(&name.as_str()); + let name = &name.as_str(); Some(unsafe { Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, - name.as_ptr(), + name.as_ptr().cast(), + name.len(), actual_type_metadata, unknown_file_metadata(cx), 0, @@ -2191,10 +2222,9 @@ fn create_struct_stub( ) -> &'ll DICompositeType { let (struct_size, struct_align) = cx.size_and_align_of(struct_type); - let name = SmallCStr::new(struct_type_name); - let unique_type_id = SmallCStr::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id), - ); + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id); + let metadata_stub = unsafe { // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null // pointer will lead to hard to trace and debug LLVM assertions @@ -2204,7 +2234,8 @@ fn create_struct_stub( llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), containing_scope, - name.as_ptr(), + struct_type_name.as_ptr().cast(), + struct_type_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, struct_size.bits(), @@ -2214,7 +2245,8 @@ fn create_struct_stub( empty_array, 0, None, - unique_type_id.as_ptr(), + unique_type_id.as_ptr().cast(), + unique_type_id.len(), ) }; @@ -2230,10 +2262,9 @@ fn create_union_stub( ) -> &'ll DICompositeType { let (union_size, union_align) = cx.size_and_align_of(union_type); - let name = SmallCStr::new(union_type_name); - let unique_type_id = SmallCStr::new( - debug_context(cx).type_map.borrow().get_unique_type_id_as_string(unique_type_id), - ); + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id); + let metadata_stub = unsafe { // `LLVMRustDIBuilderCreateUnionType()` wants an empty array. A null // pointer will lead to hard to trace and debug LLVM assertions @@ -2243,7 +2274,8 @@ fn create_union_stub( llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), containing_scope, - name.as_ptr(), + union_type_name.as_ptr().cast(), + union_type_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, union_size.bits(), @@ -2251,7 +2283,8 @@ fn create_union_stub( DIFlags::FlagZero, Some(empty_array), 0, // RuntimeLang - unique_type_id.as_ptr(), + unique_type_id.as_ptr().cast(), + unique_type_id.len(), ) }; @@ -2269,10 +2302,6 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global let tcx = cx.tcx; let attrs = tcx.codegen_fn_attrs(def_id); - if attrs.flags.contains(CodegenFnAttrFlags::NO_DEBUG) { - return; - } - let no_mangle = attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE); // We may want to remove the namespace scope if we're in an extern block (see // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952). @@ -2280,22 +2309,24 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global let span = tcx.def_span(def_id); let (file_metadata, line_number) = if !span.is_dummy() { - let loc = span_start(cx, span); - (file_metadata(cx, &loc.file.name, LOCAL_CRATE), loc.line as c_uint) + let loc = cx.lookup_debug_loc(span.lo()); + (file_metadata(cx, &loc.file.name, LOCAL_CRATE), loc.line) } else { - (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER) + (unknown_file_metadata(cx), None) }; let is_local_to_unit = is_node_local_to_unit(cx, def_id); let variable_type = Instance::mono(cx.tcx, def_id).monomorphic_ty(cx.tcx); let type_metadata = type_metadata(cx, variable_type, span); - let var_name = SmallCStr::new(&tcx.item_name(def_id).as_str()); + let var_name = tcx.item_name(def_id).as_str(); let linkage_name = if no_mangle { None } else { - let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)); - Some(SmallCStr::new(&linkage_name.name.as_str())) + Some(mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name.as_str()) }; + // When empty, linkage_name field is omitted, + // which is what we want for no_mangle statics + let linkage_name = linkage_name.as_deref().unwrap_or(""); let global_align = cx.align_of(variable_type); @@ -2303,12 +2334,12 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), Some(var_scope), - var_name.as_ptr(), - // If null, linkage_name field is omitted, - // which is what we want for no_mangle statics - linkage_name.as_ref().map_or(ptr::null(), |name| name.as_ptr()), + var_name.as_ptr().cast(), + var_name.len(), + linkage_name.as_ptr().cast(), + linkage_name.len(), file_metadata, - line_number, + line_number.unwrap_or(UNKNOWN_LINE_NUMBER), type_metadata, is_local_to_unit, global, @@ -2334,8 +2365,7 @@ pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: & // pointer will lead to hard to trace and debug LLVM assertions // later on in `llvm/lib/IR/Value.cpp`. let empty_array = create_DIArray(DIB(cx), &[]); - - let name = const_cstr!("vtable"); + let name = "vtable"; // Create a new one each time. We don't want metadata caching // here, because each vtable will refer to a unique containing @@ -2343,7 +2373,8 @@ pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: & let vtable_type = llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), NO_SCOPE_METADATA, - name.as_ptr(), + name.as_ptr().cast(), + name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, Size::ZERO.bits(), @@ -2353,14 +2384,18 @@ pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: & empty_array, 0, Some(type_metadata), - name.as_ptr(), + name.as_ptr().cast(), + name.len(), ); + let linkage_name = ""; llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), NO_SCOPE_METADATA, - name.as_ptr(), - ptr::null(), + name.as_ptr().cast(), + name.len(), + linkage_name.as_ptr().cast(), + linkage_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, vtable_type, diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 9ebb2605e8c..86ef6f9bee4 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -3,17 +3,15 @@ mod doc; use rustc_codegen_ssa::mir::debuginfo::VariableKind::*; -use self::metadata::{file_metadata, type_metadata, TypeMap}; +use self::metadata::{file_metadata, type_metadata, TypeMap, UNKNOWN_LINE_NUMBER}; use self::namespace::mangled_name_of_instance; use self::type_names::compute_debuginfo_type_name; -use self::utils::{create_DIArray, is_node_local_to_unit}; -pub(crate) use self::utils::{span_start, DIB}; +use self::utils::{create_DIArray, is_node_local_to_unit, DIB}; use crate::llvm; use crate::llvm::debuginfo::{ DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DISPFlags, DIScope, DIType, DIVariable, }; -use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc::ty::subst::{GenericArgKind, SubstsRef}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; @@ -22,25 +20,23 @@ use crate::builder::Builder; use crate::common::CodegenCx; use crate::value::Value; use rustc::mir; -use rustc::session::config::{self, DebugInfo}; -use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty}; +use rustc::ty::{self, Instance, ParamEnv, Ty}; use rustc_codegen_ssa::debuginfo::type_names; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::small_c_str::SmallCStr; use rustc_index::vec::IndexVec; +use rustc_session::config::{self, DebugInfo}; use libc::c_uint; use log::debug; use std::cell::RefCell; -use std::ffi::CString; use rustc::ty::layout::{self, HasTyCtxt, LayoutOf, Size}; +use rustc_ast::ast; use rustc_codegen_ssa::traits::*; use rustc_span::symbol::Symbol; use rustc_span::{self, BytePos, Span}; use smallvec::SmallVec; -use syntax::ast; mod create_scope_map; pub mod gdb; @@ -246,12 +242,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { return None; } - if let InstanceDef::Item(def_id) = instance.def { - if self.tcx().codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_DEBUG) { - return None; - } - } - let span = mir.span; // This can be the case for functions inlined from another crate @@ -262,7 +252,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let def_id = instance.def_id(); let containing_scope = get_containing_scope(self, instance); - let loc = span_start(self, span); + let loc = self.lookup_debug_loc(span.lo()); let file_metadata = file_metadata(self, &loc.file.name, def_id.krate); let function_type_metadata = unsafe { @@ -285,13 +275,11 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // Get the linkage_name, which is just the symbol name let linkage_name = mangled_name_of_instance(self, instance); + let linkage_name = linkage_name.name.as_str(); // FIXME(eddyb) does this need to be separate from `loc.line` for some reason? let scope_line = loc.line; - let function_name = CString::new(name).unwrap(); - let linkage_name = SmallCStr::new(&linkage_name.name.as_str()); - let mut flags = DIFlags::FlagPrototyped; if fn_abi.ret.layout.abi.is_uninhabited() { @@ -315,12 +303,14 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMRustDIBuilderCreateFunction( DIB(self), containing_scope, - function_name.as_ptr(), - linkage_name.as_ptr(), + name.as_ptr().cast(), + name.len(), + linkage_name.as_ptr().cast(), + linkage_name.len(), file_metadata, - loc.line as c_uint, + loc.line.unwrap_or(UNKNOWN_LINE_NUMBER), function_type_metadata, - scope_line as c_uint, + scope_line.unwrap_or(UNKNOWN_LINE_NUMBER), flags, spflags, llfn, @@ -436,12 +426,13 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_metadata(cx, actual_type, rustc_span::DUMMY_SP); - let name = SmallCStr::new(&name.as_str()); + let name = name.as_str(); Some(unsafe { Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, - name.as_ptr(), + name.as_ptr().cast(), + name.len(), actual_type_metadata, file_metadata, 0, @@ -547,7 +538,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { variable_kind: VariableKind, span: Span, ) -> &'ll DIVariable { - let loc = span_start(self, span); + let loc = self.lookup_debug_loc(span.lo()); let file_metadata = file_metadata(self, &loc.file.name, dbg_context.defining_crate); let type_metadata = type_metadata(self, variable_type, span); @@ -558,15 +549,16 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { }; let align = self.align_of(variable_type); - let name = SmallCStr::new(&variable_name.as_str()); + let name = variable_name.as_str(); unsafe { llvm::LLVMRustDIBuilderCreateVariable( DIB(self), dwarf_tag, scope_metadata, - name.as_ptr(), + name.as_ptr().cast(), + name.len(), file_metadata, - loc.line as c_uint, + loc.line.unwrap_or(UNKNOWN_LINE_NUMBER), type_metadata, true, DIFlags::FlagZero, diff --git a/src/librustc_codegen_llvm/debuginfo/namespace.rs b/src/librustc_codegen_llvm/debuginfo/namespace.rs index 582f4952074..55a3540809b 100644 --- a/src/librustc_codegen_llvm/debuginfo/namespace.rs +++ b/src/librustc_codegen_llvm/debuginfo/namespace.rs @@ -1,6 +1,5 @@ // Namespace Handling. -use super::metadata::{unknown_file_metadata, UNKNOWN_LINE_NUMBER}; use super::utils::{debug_context, DIB}; use rustc::ty::{self, Instance}; @@ -10,8 +9,6 @@ use crate::llvm::debuginfo::DIScope; use rustc::hir::map::DefPathData; use rustc_hir::def_id::DefId; -use rustc_data_structures::small_c_str::SmallCStr; - pub fn mangled_name_of_instance<'a, 'tcx>( cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tcx>, @@ -34,16 +31,15 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate), data => data.as_symbol(), }; - - let namespace_name = SmallCStr::new(&namespace_name.as_str()); + let namespace_name = namespace_name.as_str(); let scope = unsafe { llvm::LLVMRustDIBuilderCreateNameSpace( DIB(cx), parent_scope, - namespace_name.as_ptr(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, + namespace_name.as_ptr().cast(), + namespace_name.len(), + false, // ExportSymbols (only relevant for C++ anonymous namespaces) ) }; diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs index 1f871c7d207..66ae9d72c3e 100644 --- a/src/librustc_codegen_llvm/debuginfo/source_loc.rs +++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs @@ -1,32 +1,58 @@ -use super::metadata::UNKNOWN_COLUMN_NUMBER; -use super::utils::{debug_context, span_start}; +use super::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER}; +use super::utils::debug_context; use crate::common::CodegenCx; use crate::llvm::debuginfo::DIScope; use crate::llvm::{self, Value}; use rustc_codegen_ssa::traits::*; -use libc::c_uint; -use rustc_span::{Pos, Span}; +use rustc_data_structures::sync::Lrc; +use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span}; + +/// A source code location used to generate debug information. +pub struct DebugLoc { + /// Information about the original source file. + pub file: Lrc, + /// The (1-based) line number. + pub line: Option, + /// The (1-based) column number. + pub col: Option, +} impl CodegenCx<'ll, '_> { - pub fn create_debug_loc(&self, scope: &'ll DIScope, span: Span) -> &'ll Value { - let loc = span_start(self, span); + /// Looks up debug source information about a `BytePos`. + pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc { + let (file, line, col) = match self.sess().source_map().lookup_line(pos) { + Ok(SourceFileAndLine { sf: file, line }) => { + let line_pos = file.line_begin_pos(pos); + + // Use 1-based indexing. + let line = (line + 1) as u32; + let col = (pos - line_pos).to_u32() + 1; + + (file, Some(line), Some(col)) + } + Err(file) => (file, None, None), + }; - // For MSVC, set the column number to zero. + // For MSVC, omit the column number. // Otherwise, emit it. This mimics clang behaviour. // See discussion in https://github.com/rust-lang/rust/issues/42921 - let col_used = if self.sess().target.target.options.is_like_msvc { - UNKNOWN_COLUMN_NUMBER + if self.sess().target.target.options.is_like_msvc { + DebugLoc { file, line, col: None } } else { - loc.col.to_usize() as c_uint - }; + DebugLoc { file, line, col } + } + } + + pub fn create_debug_loc(&self, scope: &'ll DIScope, span: Span) -> &'ll Value { + let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo()); unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation( debug_context(self).llcontext, - loc.line as c_uint, - col_used, + line.unwrap_or(UNKNOWN_LINE_NUMBER), + col.unwrap_or(UNKNOWN_COLUMN_NUMBER), scope, None, ) diff --git a/src/librustc_codegen_llvm/debuginfo/utils.rs b/src/librustc_codegen_llvm/debuginfo/utils.rs index 4e17387e057..bef40decdf3 100644 --- a/src/librustc_codegen_llvm/debuginfo/utils.rs +++ b/src/librustc_codegen_llvm/debuginfo/utils.rs @@ -9,9 +9,6 @@ use rustc_hir::def_id::DefId; use crate::common::CodegenCx; use crate::llvm; use crate::llvm::debuginfo::{DIArray, DIBuilder, DIDescriptor, DIScope}; -use rustc_codegen_ssa::traits::*; - -use rustc_span::Span; pub fn is_node_local_to_unit(cx: &CodegenCx<'_, '_>, def_id: DefId) -> bool { // The is_local_to_unit flag indicates whether a function is local to the @@ -32,11 +29,6 @@ pub fn create_DIArray(builder: &DIBuilder<'ll>, arr: &[Option<&'ll DIDescriptor> }; } -/// Returns rustc_span::Loc corresponding to the beginning of the span -pub fn span_start(cx: &CodegenCx<'_, '_>, span: Span) -> rustc_span::Loc { - cx.sess().source_map().lookup_char_pos(span.lo()) -} - #[inline] pub fn debug_context(cx: &'a CodegenCx<'ll, 'tcx>) -> &'a CrateDebugContext<'ll, 'tcx> { cx.dbg_cx.as_ref().unwrap() diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs index 691f32dd85a..fab6321186b 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -21,7 +21,6 @@ use crate::value::Value; use log::debug; use rustc::ty::Ty; use rustc_codegen_ssa::traits::*; -use rustc_data_structures::small_c_str::SmallCStr; /// Declare a function. /// @@ -34,8 +33,9 @@ fn declare_raw_fn( ty: &'ll Type, ) -> &'ll Value { debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty); - let namebuf = SmallCStr::new(name); - let llfn = unsafe { llvm::LLVMRustGetOrInsertFunction(cx.llmod, namebuf.as_ptr(), ty) }; + let llfn = unsafe { + llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_ptr().cast(), name.len(), ty) + }; llvm::SetFunctionCallConv(llfn, callconv); // Function addresses in Rust are never significant, allowing functions to @@ -83,8 +83,7 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn get_declared_value(&self, name: &str) -> Option<&'ll Value> { debug!("get_declared_value(name={:?})", name); - let namebuf = SmallCStr::new(name); - unsafe { llvm::LLVMRustGetNamedValue(self.llmod, namebuf.as_ptr()) } + unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_ptr().cast(), name.len()) } } fn get_defined_value(&self, name: &str) -> Option<&'ll Value> { diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 031837c1efb..1ddfde526fa 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -10,6 +10,7 @@ use crate::value::Value; use rustc::ty::layout::{self, FnAbiExt, HasTyCtxt, LayoutOf, Primitive}; use rustc::ty::{self, Ty}; use rustc::{bug, span_bug}; +use rustc_ast::ast; use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::glue; @@ -18,7 +19,6 @@ use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::MemFlags; use rustc_hir as hir; use rustc_target::abi::HasDataLayout; -use syntax::ast; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::traits::*; @@ -193,28 +193,10 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { .tcx .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) .unwrap(); - OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self) + OperandRef::from_const(self, ty_name, ret_ty).immediate_or_packed_pair(self) } - "init" => { - let ty = substs.type_at(0); - if !self.layout_of(ty).is_zst() { - // Just zero out the stack slot. - // If we store a zero constant, LLVM will drown in vreg allocation for large - // data structures, and the generated code will be awful. (A telltale sign of - // this is large quantities of `mov [byte ptr foo],0` in the generated code.) - memset_intrinsic( - self, - false, - ty, - llresult, - self.const_u8(0), - self.const_usize(1), - ); - } - return; - } - // Effectively no-ops - "uninit" | "forget" => { + // Effectively no-op + "forget" => { return; } "offset" => { @@ -851,19 +833,21 @@ fn memset_intrinsic( fn try_intrinsic( bx: &mut Builder<'a, 'll, 'tcx>, - func: &'ll Value, + try_func: &'ll Value, data: &'ll Value, - local_ptr: &'ll Value, + catch_func: &'ll Value, dest: &'ll Value, ) { if bx.sess().no_landing_pads() { - bx.call(func, &[data], None); - let ptr_align = bx.tcx().data_layout.pointer_align.abi; - bx.store(bx.const_null(bx.type_i8p()), dest, ptr_align); + bx.call(try_func, &[data], None); + // Return 0 unconditionally from the intrinsic call; + // we can never unwind. + let ret_align = bx.tcx().data_layout.i32_align.abi; + bx.store(bx.const_i32(0), dest, ret_align); } else if wants_msvc_seh(bx.sess()) { - codegen_msvc_try(bx, func, data, local_ptr, dest); + codegen_msvc_try(bx, try_func, data, catch_func, dest); } else { - codegen_gnu_try(bx, func, data, local_ptr, dest); + codegen_gnu_try(bx, try_func, data, catch_func, dest); } } @@ -876,9 +860,9 @@ fn try_intrinsic( // as the old ones are still more optimized. fn codegen_msvc_try( bx: &mut Builder<'a, 'll, 'tcx>, - func: &'ll Value, + try_func: &'ll Value, data: &'ll Value, - local_ptr: &'ll Value, + catch_func: &'ll Value, dest: &'ll Value, ) { let llfn = get_rust_try_fn(bx, &mut |mut bx| { @@ -890,15 +874,15 @@ fn codegen_msvc_try( let mut catchpad = bx.build_sibling_block("catchpad"); let mut caught = bx.build_sibling_block("caught"); - let func = llvm::get_param(bx.llfn(), 0); + let try_func = llvm::get_param(bx.llfn(), 0); let data = llvm::get_param(bx.llfn(), 1); - let local_ptr = llvm::get_param(bx.llfn(), 2); + let catch_func = llvm::get_param(bx.llfn(), 2); // We're generating an IR snippet that looks like: // - // declare i32 @rust_try(%func, %data, %ptr) { - // %slot = alloca [2 x i64] - // invoke %func(%data) to label %normal unwind label %catchswitch + // declare i32 @rust_try(%try_func, %data, %catch_func) { + // %slot = alloca u8* + // invoke %try_func(%data) to label %normal unwind label %catchswitch // // normal: // ret i32 0 @@ -908,8 +892,8 @@ fn codegen_msvc_try( // // catchpad: // %tok = catchpad within %cs [%type_descriptor, 0, %slot] - // %ptr[0] = %slot[0] - // %ptr[1] = %slot[1] + // %ptr = load %slot + // call %catch_func(%data, %ptr) // catchret from %tok to label %caught // // caught: @@ -926,32 +910,57 @@ fn codegen_msvc_try( // ~rust_panic(); // // uint64_t x[2]; - // } + // }; // - // int bar(void (*foo)(void), uint64_t *ret) { + // int __rust_try( + // void (*try_func)(void*), + // void *data, + // void (*catch_func)(void*, void*) noexcept + // ) { // try { - // foo(); + // try_func(data); // return 0; // } catch(rust_panic& a) { - // ret[0] = a.x[0]; - // ret[1] = a.x[1]; - // a.x[0] = 0; + // catch_func(data, &a); // return 1; // } // } // // More information can be found in libstd's seh.rs implementation. - let i64_2 = bx.type_array(bx.type_i64(), 2); - let i64_2_ptr = bx.type_ptr_to(i64_2); let ptr_align = bx.tcx().data_layout.pointer_align.abi; - let slot = bx.alloca(i64_2_ptr, ptr_align); - bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None); + let slot = bx.alloca(bx.type_i8p(), ptr_align); + bx.invoke(try_func, &[data], normal.llbb(), catchswitch.llbb(), None); normal.ret(bx.const_i32(0)); let cs = catchswitch.catch_switch(None, None, 1); catchswitch.add_handler(cs, catchpad.llbb()); + // We can't use the TypeDescriptor defined in libpanic_unwind because it + // might be in another DLL and the SEH encoding only supports specifying + // a TypeDescriptor from the current module. + // + // However this isn't an issue since the MSVC runtime uses string + // comparison on the type name to match TypeDescriptors rather than + // pointer equality. + // + // So instead we generate a new TypeDescriptor in each module that uses + // `try` and let the linker merge duplicate definitions in the same + // module. + // + // When modifying, make sure that the type_name string exactly matches + // the one used in src/libpanic_unwind/seh.rs. + let type_info_vtable = bx.declare_global("??_7type_info@@6B@", bx.type_i8p()); + let type_name = bx.const_bytes(b"rust_panic\0"); + let type_info = + bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_i8p()), type_name], false); + let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info)); + unsafe { + llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage); + llvm::SetUniqueComdat(bx.llmod, tydesc); + llvm::LLVMSetInitializer(tydesc, type_info); + } + // The flag value of 8 indicates that we are catching the exception by // reference instead of by value. We can't use catch by value because // that requires copying the exception object, which we don't support @@ -959,23 +968,9 @@ fn codegen_msvc_try( // // Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang let flags = bx.const_i32(8); - let tydesc = match bx.tcx().lang_items().eh_catch_typeinfo() { - Some(did) => bx.get_static(did), - None => bug!("eh_catch_typeinfo not defined, but needed for SEH unwinding"), - }; let funclet = catchpad.catch_pad(cs, &[tydesc, flags, slot]); - - let i64_align = bx.tcx().data_layout.i64_align.abi; - let payload_ptr = catchpad.load(slot, ptr_align); - let payload = catchpad.load(payload_ptr, i64_align); - let local_ptr = catchpad.bitcast(local_ptr, bx.type_ptr_to(i64_2)); - catchpad.store(payload, local_ptr, i64_align); - - // Clear the first word of the exception so avoid double-dropping it. - // This will be read by the destructor which is implicitly called at the - // end of the catch block by the runtime. - let payload_0_ptr = catchpad.inbounds_gep(payload_ptr, &[bx.const_i32(0), bx.const_i32(0)]); - catchpad.store(bx.const_u64(0), payload_0_ptr, i64_align); + let ptr = catchpad.load(slot, ptr_align); + catchpad.call(catch_func, &[data, ptr], Some(&funclet)); catchpad.catch_ret(&funclet, caught.llbb()); @@ -984,7 +979,7 @@ fn codegen_msvc_try( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llfn, &[func, data, local_ptr], None); + let ret = bx.call(llfn, &[try_func, data, catch_func], None); let i32_align = bx.tcx().data_layout.i32_align.abi; bx.store(ret, dest, i32_align); } @@ -1002,38 +997,34 @@ fn codegen_msvc_try( // the right personality function. fn codegen_gnu_try( bx: &mut Builder<'a, 'll, 'tcx>, - func: &'ll Value, + try_func: &'ll Value, data: &'ll Value, - local_ptr: &'ll Value, + catch_func: &'ll Value, dest: &'ll Value, ) { let llfn = get_rust_try_fn(bx, &mut |mut bx| { // Codegens the shims described above: // // bx: - // invoke %func(%args...) normal %normal unwind %catch + // invoke %try_func(%data) normal %normal unwind %catch // // normal: // ret 0 // // catch: - // (ptr, _) = landingpad - // store ptr, %local_ptr + // (%ptr, _) = landingpad + // call %catch_func(%data, %ptr) // ret 1 - // - // Note that the `local_ptr` data passed into the `try` intrinsic is - // expected to be `*mut *mut u8` for this to actually work, but that's - // managed by the standard library. bx.sideeffect(); let mut then = bx.build_sibling_block("then"); let mut catch = bx.build_sibling_block("catch"); - let func = llvm::get_param(bx.llfn(), 0); + let try_func = llvm::get_param(bx.llfn(), 0); let data = llvm::get_param(bx.llfn(), 1); - let local_ptr = llvm::get_param(bx.llfn(), 2); - bx.invoke(func, &[data], then.llbb(), catch.llbb(), None); + let catch_func = llvm::get_param(bx.llfn(), 2); + bx.invoke(try_func, &[data], then.llbb(), catch.llbb(), None); then.ret(bx.const_i32(0)); // Type indicator for the exception being thrown. @@ -1053,15 +1044,13 @@ fn codegen_gnu_try( }; catch.add_clause(vals, tydesc); let ptr = catch.extract_value(vals, 0); - let ptr_align = bx.tcx().data_layout.pointer_align.abi; - let bitcast = catch.bitcast(local_ptr, bx.type_ptr_to(bx.type_i8p())); - catch.store(ptr, bitcast, ptr_align); + catch.call(catch_func, &[data, ptr], None); catch.ret(bx.const_i32(1)); }); // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). - let ret = bx.call(llfn, &[func, data, local_ptr], None); + let ret = bx.call(llfn, &[try_func, data, catch_func], None); let i32_align = bx.tcx().data_layout.i32_align.abi; bx.store(ret, dest, i32_align); } @@ -1084,6 +1073,8 @@ fn gen_fn<'ll, 'tcx>( )); let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]); let llfn = cx.declare_fn(name, &fn_abi); + cx.set_frame_pointer_elimination(llfn); + cx.apply_target_cpu_attr(llfn); // FIXME(eddyb) find a nicer way to do this. unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) }; let bx = Builder::new_block(cx, llfn, "entry-block"); @@ -1106,15 +1097,22 @@ fn get_rust_try_fn<'ll, 'tcx>( // Define the type up front for the signature of the rust_try function. let tcx = cx.tcx; let i8p = tcx.mk_mut_ptr(tcx.types.i8); - let fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( + let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( iter::once(i8p), tcx.mk_unit(), false, hir::Unsafety::Unsafe, Abi::Rust, ))); + let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( + [i8p, i8p].iter().cloned(), + tcx.mk_unit(), + false, + hir::Unsafety::Unsafe, + Abi::Rust, + ))); let output = tcx.types.i32; - let rust_try = gen_fn(cx, "__rust_try", vec![fn_ty, i8p, i8p], output, codegen); + let rust_try = gen_fn(cx, "__rust_try", vec![try_fn_ty, i8p, catch_fn_ty], output, codegen); cx.rust_try_fn.set(Some(rust_try)); rust_try } diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index dbb8ac45840..e1573e0047b 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -15,35 +15,35 @@ #![recursion_limit = "256"] use back::write::{create_informational_target_machine, create_target_machine}; -use rustc_span::symbol::Symbol; pub use llvm_util::target_features; -use rustc::dep_graph::WorkProduct; +use rustc::dep_graph::{DepGraph, WorkProduct}; +use rustc::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; +use rustc::ty::{self, TyCtxt}; +use rustc::util::common::ErrorReported; +use rustc_ast::expand::allocator::AllocatorKind; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; use rustc_codegen_ssa::traits::*; +use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_errors::{FatalError, Handler}; +use rustc_serialize::json; +use rustc_session::config::{self, OptLevel, OutputFilenames, PrintRequest}; +use rustc_session::Session; +use rustc_span::symbol::Symbol; + use std::any::Any; use std::ffi::CStr; use std::fs; use std::sync::Arc; -use syntax::expand::allocator::AllocatorKind; - -use rustc::dep_graph::DepGraph; -use rustc::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; -use rustc::session::config::{self, OptLevel, OutputFilenames, PrintRequest}; -use rustc::session::Session; -use rustc::ty::{self, TyCtxt}; -use rustc::util::common::ErrorReported; -use rustc_codegen_ssa::ModuleCodegen; -use rustc_codegen_utils::codegen_backend::CodegenBackend; -use rustc_serialize::json; mod back { pub mod archive; pub mod bytecode; pub mod lto; + mod profiling; pub mod write; } diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 859c53ce44c..09702355b02 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -381,10 +381,10 @@ pub enum AsmDialect { } impl AsmDialect { - pub fn from_generic(asm: syntax::ast::AsmDialect) -> Self { + pub fn from_generic(asm: rustc_ast::ast::AsmDialect) -> Self { match asm { - syntax::ast::AsmDialect::Att => AsmDialect::Att, - syntax::ast::AsmDialect::Intel => AsmDialect::Intel, + rustc_ast::ast::AsmDialect::Att => AsmDialect::Att, + rustc_ast::ast::AsmDialect::Intel => AsmDialect::Intel, } } } @@ -694,8 +694,8 @@ pub mod debuginfo { } impl DebugEmissionKind { - pub fn from_generic(kind: rustc::session::config::DebugInfo) -> Self { - use rustc::session::config::DebugInfo; + pub fn from_generic(kind: rustc_session::config::DebugInfo) -> Self { + use rustc_session::config::DebugInfo; match kind { DebugInfo::None => DebugEmissionKind::NoDebug, DebugInfo::Limited => DebugEmissionKind::LineTablesOnly, @@ -709,6 +709,10 @@ extern "C" { pub type ModuleBuffer; } +pub type SelfProfileBeforePassCallback = + unsafe extern "C" fn(*mut c_void, *const c_char, *const c_char); +pub type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void); + extern "C" { pub fn LLVMRustInstallFatalErrorHandler(); @@ -728,7 +732,7 @@ extern "C" { /// See Module::setModuleInlineAsm. pub fn LLVMSetModuleInlineAsm(M: &Module, Asm: *const c_char); - pub fn LLVMRustAppendModuleInlineAsm(M: &Module, Asm: *const c_char); + pub fn LLVMRustAppendModuleInlineAsm(M: &Module, Asm: *const c_char, AsmLen: size_t); /// See llvm::LLVMTypeKind::getTypeID. pub fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind; @@ -875,13 +879,18 @@ extern "C" { pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); - pub fn LLVMRustGetNamedValue(M: &Module, Name: *const c_char) -> Option<&Value>; + pub fn LLVMRustGetNamedValue( + M: &Module, + Name: *const c_char, + NameLen: size_t, + ) -> Option<&Value>; pub fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); // Operations on functions pub fn LLVMRustGetOrInsertFunction( M: &'a Module, Name: *const c_char, + NameLen: size_t, FunctionTy: &'a Type, ) -> &'a Value; pub fn LLVMSetFunctionCallConv(Fn: &Value, CC: c_uint); @@ -1331,7 +1340,6 @@ extern "C" { Args: *const &'a Value, NumArgs: c_uint, Bundle: Option<&OperandBundleDef<'a>>, - Name: *const c_char, ) -> &'a Value; pub fn LLVMRustBuildMemCpy( B: &Builder<'a>, @@ -1580,12 +1588,18 @@ extern "C" { pub fn LLVMRustInlineAsm( Ty: &Type, AsmString: *const c_char, + AsmStringLen: size_t, Constraints: *const c_char, + ConstraintsLen: size_t, SideEffects: Bool, AlignStack: Bool, Dialect: AsmDialect, ) -> &Value; - pub fn LLVMRustInlineAsmVerify(Ty: &Type, Constraints: *const c_char) -> bool; + pub fn LLVMRustInlineAsmVerify( + Ty: &Type, + Constraints: *const c_char, + ConstraintsLen: size_t, + ) -> bool; pub fn LLVMRustDebugMetadataVersion() -> u32; pub fn LLVMRustVersionMajor() -> u32; @@ -1606,17 +1620,21 @@ extern "C" { Lang: c_uint, File: &'a DIFile, Producer: *const c_char, + ProducerLen: size_t, isOptimized: bool, Flags: *const c_char, RuntimeVer: c_uint, SplitName: *const c_char, + SplitNameLen: size_t, kind: DebugEmissionKind, ) -> &'a DIDescriptor; pub fn LLVMRustDIBuilderCreateFile( Builder: &DIBuilder<'a>, Filename: *const c_char, + FilenameLen: size_t, Directory: *const c_char, + DirectoryLen: size_t, ) -> &'a DIFile; pub fn LLVMRustDIBuilderCreateSubroutineType( @@ -1629,7 +1647,9 @@ extern "C" { Builder: &DIBuilder<'a>, Scope: &'a DIDescriptor, Name: *const c_char, + NameLen: size_t, LinkageName: *const c_char, + LinkageNameLen: size_t, File: &'a DIFile, LineNo: c_uint, Ty: &'a DIType, @@ -1644,6 +1664,7 @@ extern "C" { pub fn LLVMRustDIBuilderCreateBasicType( Builder: &DIBuilder<'a>, Name: *const c_char, + NameLen: size_t, SizeInBits: u64, AlignInBits: u32, Encoding: c_uint, @@ -1654,13 +1675,16 @@ extern "C" { PointeeTy: &'a DIType, SizeInBits: u64, AlignInBits: u32, + AddressSpace: c_uint, Name: *const c_char, + NameLen: size_t, ) -> &'a DIDerivedType; pub fn LLVMRustDIBuilderCreateStructType( Builder: &DIBuilder<'a>, Scope: Option<&'a DIDescriptor>, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNumber: c_uint, SizeInBits: u64, @@ -1671,12 +1695,14 @@ extern "C" { RunTimeLang: c_uint, VTableHolder: Option<&'a DIType>, UniqueId: *const c_char, + UniqueIdLen: size_t, ) -> &'a DICompositeType; pub fn LLVMRustDIBuilderCreateMemberType( Builder: &DIBuilder<'a>, Scope: &'a DIDescriptor, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNo: c_uint, SizeInBits: u64, @@ -1690,6 +1716,7 @@ extern "C" { Builder: &DIBuilder<'a>, Scope: &'a DIScope, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNumber: c_uint, SizeInBits: u64, @@ -1718,7 +1745,9 @@ extern "C" { Builder: &DIBuilder<'a>, Context: Option<&'a DIScope>, Name: *const c_char, + NameLen: size_t, LinkageName: *const c_char, + LinkageNameLen: size_t, File: &'a DIFile, LineNo: c_uint, Ty: &'a DIType, @@ -1733,6 +1762,7 @@ extern "C" { Tag: c_uint, Scope: &'a DIDescriptor, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNo: c_uint, Ty: &'a DIType, @@ -1775,13 +1805,16 @@ extern "C" { pub fn LLVMRustDIBuilderCreateEnumerator( Builder: &DIBuilder<'a>, Name: *const c_char, - Val: u64, + NameLen: size_t, + Value: i64, + IsUnsigned: bool, ) -> &'a DIEnumerator; pub fn LLVMRustDIBuilderCreateEnumerationType( Builder: &DIBuilder<'a>, Scope: &'a DIScope, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNumber: c_uint, SizeInBits: u64, @@ -1795,6 +1828,7 @@ extern "C" { Builder: &DIBuilder<'a>, Scope: &'a DIScope, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNumber: c_uint, SizeInBits: u64, @@ -1803,12 +1837,14 @@ extern "C" { Elements: Option<&'a DIArray>, RunTimeLang: c_uint, UniqueId: *const c_char, + UniqueIdLen: size_t, ) -> &'a DIType; pub fn LLVMRustDIBuilderCreateVariantPart( Builder: &DIBuilder<'a>, Scope: &'a DIScope, Name: *const c_char, + NameLen: size_t, File: &'a DIFile, LineNo: c_uint, SizeInBits: u64, @@ -1817,6 +1853,7 @@ extern "C" { Discriminator: Option<&'a DIDerivedType>, Elements: &'a DIArray, UniqueId: *const c_char, + UniqueIdLen: size_t, ) -> &'a DIDerivedType; pub fn LLVMSetUnnamedAddr(GlobalVar: &Value, UnnamedAddr: Bool); @@ -1825,6 +1862,7 @@ extern "C" { Builder: &DIBuilder<'a>, Scope: Option<&'a DIScope>, Name: *const c_char, + NameLen: size_t, Ty: &'a DIType, File: &'a DIFile, LineNo: c_uint, @@ -1835,8 +1873,8 @@ extern "C" { Builder: &DIBuilder<'a>, Scope: Option<&'a DIScope>, Name: *const c_char, - File: &'a DIFile, - LineNo: c_uint, + NameLen: size_t, + ExportSymbols: bool, ) -> &'a DINameSpace; pub fn LLVMRustDICompositeTypeReplaceArrays( @@ -1957,6 +1995,9 @@ extern "C" { SanitizerOptions: Option<&SanitizerOptions>, PGOGenPath: *const c_char, PGOUsePath: *const c_char, + llvm_selfprofiler: *mut c_void, + begin_callback: SelfProfileBeforePassCallback, + end_callback: SelfProfileAfterPassCallback, ); pub fn LLVMRustPrintModule( M: &'a Module, diff --git a/src/librustc_codegen_llvm/llvm/mod.rs b/src/librustc_codegen_llvm/llvm/mod.rs index 96014cbee5d..a083e14979c 100644 --- a/src/librustc_codegen_llvm/llvm/mod.rs +++ b/src/librustc_codegen_llvm/llvm/mod.rs @@ -185,12 +185,12 @@ impl Drop for SectionIter<'a> { } } -pub fn mk_section_iter(llof: &'a ffi::ObjectFile) -> SectionIter<'a> { +pub fn mk_section_iter(llof: &ffi::ObjectFile) -> SectionIter<'_> { unsafe { SectionIter { llsi: LLVMGetSections(llof) } } } /// Safe wrapper around `LLVMGetParam`, because segfaults are no fun. -pub fn get_param(llfn: &'a Value, index: c_uint) -> &'a Value { +pub fn get_param(llfn: &Value, index: c_uint) -> &Value { unsafe { assert!( index < LLVMCountParams(llfn), @@ -203,7 +203,7 @@ pub fn get_param(llfn: &'a Value, index: c_uint) -> &'a Value { } /// Safe wrapper for `LLVMGetValueName2` into a byte slice -pub fn get_value_name(value: &'a Value) -> &'a [u8] { +pub fn get_value_name(value: &Value) -> &[u8] { unsafe { let mut len = 0; let data = LLVMGetValueName2(value, &mut len); diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 6d3498f8b80..5e924c9af84 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -2,10 +2,10 @@ use crate::back::write::create_informational_target_machine; use crate::llvm; use libc::c_int; use rustc::bug; -use rustc::session::config::PrintRequest; -use rustc::session::Session; use rustc_data_structures::fx::FxHashSet; use rustc_feature::UnstableFeatures; +use rustc_session::config::PrintRequest; +use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::symbol::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy}; @@ -61,7 +61,7 @@ unsafe fn configure_llvm(sess: &Session) { let sess_args = cg_opts.chain(tg_opts); let user_specified_args: FxHashSet<_> = - sess_args.clone().map(|s| llvm_arg_to_arg_name(s)).filter(|s| s.len() > 0).collect(); + sess_args.clone().map(|s| llvm_arg_to_arg_name(s)).filter(|s| !s.is_empty()).collect(); { // This adds the given argument to LLVM. Unless `force` is true diff --git a/src/librustc_codegen_llvm/sir.rs b/src/librustc_codegen_llvm/sir.rs index 03df9c38624..8a56b793d50 100644 --- a/src/librustc_codegen_llvm/sir.rs +++ b/src/librustc_codegen_llvm/sir.rs @@ -8,7 +8,6 @@ use crate::llvm::{self, BasicBlock}; use crate::value::Value; use crate::{common, ModuleLlvm}; -use rustc::session::config::OutputType; use rustc::ty::TyCtxt; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_data_structures::fx::FxHashMap; @@ -18,6 +17,7 @@ use rustc_index::{ newtype_index, vec::{Idx, IndexVec}, }; +use rustc_session::config::OutputType; use std::default::Default; use std::ffi::CString; use ykpack; diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs index 628b6fe39e6..5bc1475df23 100644 --- a/src/librustc_codegen_llvm/type_.rs +++ b/src/librustc_codegen_llvm/type_.rs @@ -12,10 +12,10 @@ use crate::common; use crate::type_of::LayoutLlvmExt; use rustc::ty::layout::{self, Align, Size, TyLayout}; use rustc::ty::Ty; +use rustc_ast::ast; use rustc_codegen_ssa::common::TypeKind; use rustc_data_structures::small_c_str::SmallCStr; use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; -use syntax::ast; use std::fmt; use std::ptr; @@ -240,7 +240,7 @@ impl Type { unsafe { llvm::LLVMIntTypeInContext(llcx, num_bits as c_uint) } } - pub fn i8p_llcx(llcx: &'ll llvm::Context) -> &'ll Type { + pub fn i8p_llcx(llcx: &llvm::Context) -> &Type { Type::i8_llcx(llcx).ptr_to() } diff --git a/src/librustc_codegen_llvm/va_arg.rs b/src/librustc_codegen_llvm/va_arg.rs index 9bc3eec60ae..a552f2cdb78 100644 --- a/src/librustc_codegen_llvm/va_arg.rs +++ b/src/librustc_codegen_llvm/va_arg.rs @@ -117,8 +117,7 @@ pub(super) fn emit_va_arg( // Windows x86_64 ("x86_64", true) => { let target_ty_size = bx.cx.size_of(target_ty).bytes(); - let indirect = - if target_ty_size > 8 || !target_ty_size.is_power_of_two() { true } else { false }; + let indirect: bool = target_ty_size > 8 || !target_ty_size.is_power_of_two(); emit_ptr_va_arg(bx, addr, target_ty, indirect, Align::from_bytes(8).unwrap(), false) } // For all other architecture/OS combinations fall back to using diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index 45c566928ec..bc8b7639d2f 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -20,7 +20,7 @@ jobserver = "0.1.11" tempfile = "3.1" rustc_serialize = { path = "../libserialize", package = "serialize" } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } rustc = { path = "../librustc" } rustc_apfloat = { path = "../librustc_apfloat" } diff --git a/src/librustc_codegen_ssa/README.md b/src/librustc_codegen_ssa/README.md index 2a3a4fcc5fc..90d991a3a4b 100644 --- a/src/librustc_codegen_ssa/README.md +++ b/src/librustc_codegen_ssa/README.md @@ -1,3 +1,3 @@ -Please read the rustc-guide chapter on [Backend Agnostic Codegen][bac]. +Please read the rustc-dev-guide chapter on [Backend Agnostic Codegen][bac]. -[bac]: https://rust-lang.github.io/rustc-guide/codegen/backend-agnostic.html +[bac]: https://rustc-dev-guide.rust-lang.org/codegen/backend-agnostic.html diff --git a/src/librustc_codegen_ssa/back/archive.rs b/src/librustc_codegen_ssa/back/archive.rs index a357c350287..f83b4b2b0c0 100644 --- a/src/librustc_codegen_ssa/back/archive.rs +++ b/src/librustc_codegen_ssa/back/archive.rs @@ -1,4 +1,4 @@ -use rustc::session::Session; +use rustc_session::Session; use rustc_span::symbol::Symbol; use std::io; diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 4a1cc05ff18..eaf16623d1b 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1,15 +1,15 @@ use rustc::middle::cstore::{EncodedMetadata, LibSource, NativeLibrary, NativeLibraryKind}; use rustc::middle::dependency_format::Linkage; -use rustc::session::config::{ +use rustc_data_structures::fx::FxHashSet; +use rustc_fs_util::fix_windows_verbatim_for_gcc; +use rustc_hir::def_id::CrateNum; +use rustc_session::config::{ self, CFGuard, DebugInfo, OutputFilenames, OutputType, PrintRequest, Sanitizer, TracerMode, }; -use rustc::session::search_paths::PathKind; +use rustc_session::search_paths::PathKind; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. -use rustc::session::{filesearch, Session}; -use rustc_data_structures::fx::FxHashSet; -use rustc_fs_util::fix_windows_verbatim_for_gcc; -use rustc_hir::def_id::CrateNum; +use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel}; @@ -187,7 +187,7 @@ pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathB if flavor == LinkerFlavor::Msvc && t.target_vendor == "uwp" { if let Some(ref tool) = msvc_tool { let original_path = tool.path(); - if let Some(ref root_lib_path) = original_path.ancestors().skip(4).next() { + if let Some(ref root_lib_path) = original_path.ancestors().nth(4) { let arch = match t.arch.as_str() { "x86_64" => Some("x64".to_string()), "x86" => Some("x86".to_string()), @@ -501,6 +501,11 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( info!("preparing {:?} to {:?}", crate_type, out_filename); let (linker, flavor) = linker_and_flavor(sess); + let any_dynamic_crate = crate_type == config::CrateType::Dylib + || codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| { + *ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic) + }); + // The invocations of cc share some flags across platforms let (pname, mut cmd) = get_linker(sess, &linker, flavor); @@ -508,7 +513,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( cmd.args(args); } if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) { - if sess.crt_static() { + if sess.crt_static(Some(crate_type)) { cmd.args(args); } } @@ -534,7 +539,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( cmd.arg(get_file_path(sess, obj)); } - if crate_type == config::CrateType::Executable && sess.crt_static() { + if crate_type == config::CrateType::Executable && sess.crt_static(Some(crate_type)) { for obj in &sess.target.target.options.pre_link_objects_exe_crt { cmd.arg(get_file_path(sess, obj)); } @@ -566,10 +571,19 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { cmd.args(args); } + if any_dynamic_crate { + if let Some(args) = sess.target.target.options.late_link_args_dynamic.get(&flavor) { + cmd.args(args); + } + } else { + if let Some(args) = sess.target.target.options.late_link_args_static.get(&flavor) { + cmd.args(args); + } + } for obj in &sess.target.target.options.post_link_objects { cmd.arg(get_file_path(sess, obj)); } - if sess.crt_static() { + if sess.crt_static(Some(crate_type)) { for obj in &sess.target.target.options.post_link_objects_crt { cmd.arg(get_file_path(sess, obj)); } @@ -1027,20 +1041,26 @@ fn get_crt_libs_path(sess: &Session) -> Option { x if x == "x86" => "i686", x => x, }; + let mingw_bits = &sess.target.target.target_pointer_width; let mingw_dir = format!("{}-w64-mingw32", mingw_arch); // Here we have path/bin/gcc but we need path/ let mut path = linker_path; path.pop(); path.pop(); - // Based on Clang MinGW driver - let probe_path = path.join(&mingw_dir).join("lib"); - if probe_path.exists() { - return Some(probe_path); - }; - let probe_path = path.join(&mingw_dir).join("sys-root/mingw/lib"); - if probe_path.exists() { - return Some(probe_path); - }; + // Loosely based on Clang MinGW driver + let probe_paths = vec![ + path.join(&mingw_dir).join("lib"), // Typical path + path.join(&mingw_dir).join("sys-root/mingw/lib"), // Rare path + path.join(format!( + "lib/mingw/tools/install/mingw{}/{}/lib", + &mingw_bits, &mingw_dir + )), // Chocolatey is creative + ]; + for probe_path in probe_paths { + if probe_path.join("crt2.o").exists() { + return Some(probe_path); + }; + } }; }; None @@ -1310,7 +1330,8 @@ fn link_args<'a, B: ArchiveBuilder<'a>>( let more_args = &sess.opts.cg.link_arg; let mut args = args.iter().chain(more_args.iter()).chain(used_link_args.iter()); - if is_pic(sess) && !sess.crt_static() && !args.any(|x| *x == "-static") { + if is_pic(sess) && !sess.crt_static(Some(crate_type)) && !args.any(|x| *x == "-static") + { position_independent_executable = true; } } @@ -1395,7 +1416,7 @@ fn link_args<'a, B: ArchiveBuilder<'a>>( if crate_type != config::CrateType::Executable { cmd.build_dylib(out_filename); } - if crate_type == config::CrateType::Executable && sess.crt_static() { + if crate_type == config::CrateType::Executable && sess.crt_static(Some(crate_type)) { cmd.build_static_executable(); } @@ -1541,17 +1562,25 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( // for the current implementation of the standard library. let mut group_end = None; let mut group_start = None; - let mut end_with = FxHashSet::default(); + // Crates available for linking thus far. + let mut available = FxHashSet::default(); + // Crates required to satisfy dependencies discovered so far. + let mut required = FxHashSet::default(); + let info = &codegen_results.crate_info; for &(cnum, _) in deps.iter().rev() { if let Some(missing) = info.missing_lang_items.get(&cnum) { - end_with.extend(missing.iter().cloned()); - if end_with.len() > 0 && group_end.is_none() { - group_end = Some(cnum); - } + let missing_crates = missing.iter().map(|i| info.lang_item_to_crate.get(i).copied()); + required.extend(missing_crates); + } + + required.insert(Some(cnum)); + available.insert(Some(cnum)); + + if required.len() > available.len() && group_end.is_none() { + group_end = Some(cnum); } - end_with.retain(|item| info.lang_item_to_crate.get(item) != Some(&cnum)); - if end_with.len() == 0 && group_end.is_some() { + if required.len() == available.len() && group_end.is_some() { group_start = Some(cnum); break; } diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 5aafb8a12d7..6b30ae8559d 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -2,7 +2,6 @@ use super::archive; use super::command::Command; use super::symbol_export; -use rustc_data_structures::fx::FxHashMap; use std::ffi::{OsStr, OsString}; use std::fs::{self, File}; use std::io::prelude::*; @@ -10,11 +9,12 @@ use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; use rustc::middle::dependency_format::Linkage; -use rustc::session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel}; -use rustc::session::Session; use rustc::ty::TyCtxt; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_serialize::{json, Encoder}; +use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel}; +use rustc_session::Session; use rustc_span::symbol::Symbol; use rustc_target::spec::{LinkerFlavor, LldFlavor}; diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index a6cd0c09684..8368d98884a 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -3,11 +3,11 @@ use std::sync::Arc; use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc::middle::exported_symbols::{metadata_symbol_name, ExportedSymbol, SymbolExportLevel}; -use rustc::session::config::{self, Sanitizer}; use rustc::ty::query::Providers; use rustc::ty::subst::{GenericArgKind, SubstsRef}; use rustc::ty::Instance; use rustc::ty::{SymbolName, TyCtxt}; +use rustc_ast::expand::allocator::ALLOCATOR_METHODS; use rustc_codegen_utils::symbol_names; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -15,7 +15,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::Node; use rustc_index::vec::IndexVec; -use syntax::expand::allocator::ALLOCATOR_METHODS; +use rustc_session::config::{self, Sanitizer}; pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { crates_export_threshold(&tcx.sess.crate_types.borrow()) @@ -88,7 +88,7 @@ fn reachable_non_generics_provider( // Only consider nodes that actually have exported symbols. Node::Item(&hir::Item { kind: hir::ItemKind::Static(..), .. }) | Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. }) - | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Method(..), .. }) => { + | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => { let def_id = tcx.hir().local_def_id(hir_id); let generics = tcx.generics_of(def_id); if !generics.requires_monomorphization(tcx) && diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 2b2a72b8cea..600a1593f49 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -14,11 +14,8 @@ use jobserver::{Acquired, Client}; use rustc::dep_graph::{WorkProduct, WorkProductFileKind, WorkProductId}; use rustc::middle::cstore::EncodedMetadata; use rustc::middle::exported_symbols::SymbolExportLevel; -use rustc::session::config::{ - self, Lto, OutputFilenames, OutputType, Passes, Sanitizer, SwitchWithOptPath, -}; -use rustc::session::Session; use rustc::ty::TyCtxt; +use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::profiling::TimingGuard; @@ -33,11 +30,14 @@ use rustc_incremental::{ copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess, }; use rustc_session::cgu_reuse_tracker::CguReuseTracker; +use rustc_session::config::{ + self, Lto, OutputFilenames, OutputType, Passes, Sanitizer, SwitchWithOptPath, +}; +use rustc_session::Session; use rustc_span::hygiene::ExpnId; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{sym, Symbol}; use rustc_target::spec::MergeFunctions; -use syntax::attr; use std::any::Any; use std::fs; @@ -344,9 +344,9 @@ pub fn start_async_codegen( let crate_name = tcx.crate_name(LOCAL_CRATE); let crate_hash = tcx.crate_hash(LOCAL_CRATE); - let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, sym::no_builtins); + let no_builtins = attr::contains_name(&tcx.hir().krate().item.attrs, sym::no_builtins); let subsystem = - attr::first_attr_value_str_by_name(&tcx.hir().krate().attrs, sym::windows_subsystem); + attr::first_attr_value_str_by_name(&tcx.hir().krate().item.attrs, sym::windows_subsystem); let windows_subsystem = subsystem.map(|subsystem| { if subsystem != sym::windows && subsystem != sym::console { tcx.sess.fatal(&format!( @@ -751,7 +751,7 @@ fn execute_work_item( } } -// Actual LTO type we end up chosing based on multiple factors. +// Actual LTO type we end up choosing based on multiple factors. enum ComputedLtoType { No, Thin, @@ -1262,11 +1262,11 @@ fn start_executing_work( while !codegen_done || running > 0 || (!codegen_aborted - && (work_items.len() > 0 - || needs_fat_lto.len() > 0 - || needs_thin_lto.len() > 0 - || lto_import_only_modules.len() > 0 - || main_thread_worker_state != MainThreadWorkerState::Idle)) + && !(work_items.is_empty() + && needs_fat_lto.is_empty() + && needs_thin_lto.is_empty() + && lto_import_only_modules.is_empty() + && main_thread_worker_state == MainThreadWorkerState::Idle)) { // While there are still CGUs to be codegened, the coordinator has // to decide how to utilize the compiler processes implicit Token: @@ -1275,7 +1275,7 @@ fn start_executing_work( if main_thread_worker_state == MainThreadWorkerState::Idle { if !queue_full_enough(work_items.len(), running, max_workers) { // The queue is not full enough, codegen more items: - if let Err(_) = codegen_worker_send.send(Message::CodegenItem) { + if codegen_worker_send.send(Message::CodegenItem).is_err() { panic!("Could not send Message::CodegenItem to main thread") } main_thread_worker_state = MainThreadWorkerState::Codegenning; @@ -1307,7 +1307,7 @@ fn start_executing_work( // Perform the serial work here of figuring out what we're // going to LTO and then push a bunch of work items onto our // queue to do LTO - if work_items.len() == 0 + if work_items.is_empty() && running == 0 && main_thread_worker_state == MainThreadWorkerState::Idle { @@ -1372,7 +1372,7 @@ fn start_executing_work( // Spin up what work we can, only doing this while we've got available // parallelism slots and work left to spawn. - while !codegen_aborted && work_items.len() > 0 && running < tokens.len() { + while !codegen_aborted && !work_items.is_empty() && running < tokens.len() { let (item, _) = work_items.pop().unwrap(); maybe_start_llvm_timer(prof, cgcx.config(item.module_kind()), &mut llvm_start_time); diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 1d62360d21b..1d373cdc336 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -31,8 +31,6 @@ use rustc::middle::cstore::{self, LinkagePreference}; use rustc::middle::lang_items; use rustc::middle::lang_items::StartFnLangItem; use rustc::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; -use rustc::session::config::{self, EntryFnType, Lto, OutputType}; -use rustc::session::Session; use rustc::ty::layout::{self, Align, HasTyCtxt, LayoutOf, TyLayout, VariantIdx}; use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; use rustc::ty::query::Providers; @@ -46,6 +44,8 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_index::vec::Idx; use rustc_session::cgu_reuse_tracker::CguReuse; +use rustc_session::config::{self, EntryFnType, Lto, OutputType}; +use rustc_session::Session; use rustc_span::Span; use std::cmp; @@ -437,10 +437,10 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // listing. let main_ret_ty = cx.tcx().erase_regions(&main_ret_ty.no_bound_vars().unwrap()); - if cx.get_defined_value("main").is_some() { + if cx.get_declared_value("main").is_some() { // FIXME: We should be smart and show a better diagnostic here. cx.sess() - .struct_span_err(sp, "entry symbol `main` defined multiple times") + .struct_span_err(sp, "entry symbol `main` declared multiple times") .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead") .emit(); cx.sess().abort_if_errors(); diff --git a/src/librustc_codegen_ssa/common.rs b/src/librustc_codegen_ssa/common.rs index 28b61e0b36d..147b2399502 100644 --- a/src/librustc_codegen_ssa/common.rs +++ b/src/librustc_codegen_ssa/common.rs @@ -1,8 +1,8 @@ #![allow(non_camel_case_types, non_snake_case)] -use rustc::session::Session; use rustc::ty::{Ty, TyCtxt}; use rustc_errors::struct_span_err; +use rustc_session::Session; use rustc_span::Span; use crate::base; diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index c8e83bf4890..b0ea332c709 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -21,12 +21,12 @@ use rustc::dep_graph::WorkProduct; use rustc::middle::cstore::{CrateSource, LibSource, NativeLibrary}; use rustc::middle::dependency_format::Dependencies; use rustc::middle::lang_items::LangItem; -use rustc::session::config::{OutputFilenames, OutputType, RUST_CGU_EXT}; use rustc::ty::query::Providers; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; +use rustc_session::config::{OutputFilenames, OutputType, RUST_CGU_EXT}; use rustc_span::symbol::Symbol; use std::path::{Path, PathBuf}; diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index 7bf222f4701..04680a17517 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -97,7 +97,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { fn process_place( &mut self, - place_ref: &mir::PlaceRef<'_, 'tcx>, + place_ref: &mir::PlaceRef<'tcx>, context: PlaceContext, location: Location, ) { @@ -203,7 +203,7 @@ impl> LocalAnalyzer<'mir, 'a, 'tcx, Bx> { } self.visit_place_base(&place_ref.local, context, location); - self.visit_projection(&place_ref.local, place_ref.projection, context, location); + self.visit_projection(place_ref.local, place_ref.projection, context, location); } } } diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 8349660dc3f..37d9cf1c11a 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -11,7 +11,7 @@ use crate::MemFlags; use rustc::middle::lang_items; use rustc::mir; -use rustc::mir::interpret::PanicInfo; +use rustc::mir::AssertKind; use rustc::ty::layout::{self, FnAbiExt, HasTyCtxt, LayoutOf}; use rustc::ty::{self, Instance, Ty, TypeFoldable}; use rustc_index::vec::Idx; @@ -188,15 +188,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let lp1 = bx.load_operand(lp1).immediate(); slot.storage_dead(&mut bx); - if !bx.sess().target.target.options.custom_unwind_resume { - let mut lp = bx.const_undef(self.landing_pad_type()); - lp = bx.insert_value(lp, lp0, 0); - lp = bx.insert_value(lp, lp1, 1); - bx.resume(lp); - } else { - bx.call(bx.eh_unwind_resume(), &[lp0], helper.funclet(self)); - bx.unreachable(); - } + let mut lp = bx.const_undef(self.landing_pad_type()); + lp = bx.insert_value(lp, lp0, 0); + lp = bx.insert_value(lp, lp1, 1); + bx.resume(lp); } } @@ -388,7 +383,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // checked operation, just a comparison with the minimum // value, so we have to check for the assert message. if !bx.check_overflow() { - if let PanicInfo::OverflowNeg = *msg { + if let AssertKind::OverflowNeg = *msg { const_cond = Some(expected); } } @@ -422,14 +417,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Put together the arguments to the panic entry point. let (lang_item, args) = match msg { - PanicInfo::BoundsCheck { ref len, ref index } => { + AssertKind::BoundsCheck { ref len, ref index } => { let len = self.codegen_operand(&mut bx, len).immediate(); let index = self.codegen_operand(&mut bx, index).immediate(); - (lang_items::PanicBoundsCheckFnLangItem, vec![location, index, len]) + // It's `fn panic_bounds_check(index: usize, len: usize)`, + // and `#[track_caller]` adds an implicit third argument. + (lang_items::PanicBoundsCheckFnLangItem, vec![index, len, location]) } _ => { let msg_str = Symbol::intern(msg.description()); let msg = bx.const_str(msg_str); + // It's `pub fn panic(expr: &str)`, with the wide reference being passed + // as two arguments, and `#[track_caller]` adds an implicit third argument. (lang_items::PanicFnLangItem, vec![msg.0, msg.1, location]) } }; @@ -444,6 +443,89 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup); } + /// Returns `true` if this is indeed a panic intrinsic and codegen is done. + fn codegen_panic_intrinsic( + &mut self, + helper: &TerminatorCodegenHelper<'tcx>, + bx: &mut Bx, + intrinsic: Option<&str>, + instance: Option>, + span: Span, + destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>, + cleanup: Option, + ) -> bool { + // Emit a panic or a no-op for `assert_*` intrinsics. + // These are intrinsics that compile to panics so that we can get a message + // which mentions the offending type, even from a const context. + #[derive(Debug, PartialEq)] + enum AssertIntrinsic { + Inhabited, + ZeroValid, + UninitValid, + }; + let panic_intrinsic = intrinsic.and_then(|i| match i { + // FIXME: Move to symbols instead of strings. + "assert_inhabited" => Some(AssertIntrinsic::Inhabited), + "assert_zero_valid" => Some(AssertIntrinsic::ZeroValid), + "assert_uninit_valid" => Some(AssertIntrinsic::UninitValid), + _ => None, + }); + if let Some(intrinsic) = panic_intrinsic { + use AssertIntrinsic::*; + let ty = instance.unwrap().substs.type_at(0); + let layout = bx.layout_of(ty); + let do_panic = match intrinsic { + Inhabited => layout.abi.is_uninhabited(), + // We unwrap as the error type is `!`. + ZeroValid => !layout.might_permit_raw_init(bx, /*zero:*/ true).unwrap(), + // We unwrap as the error type is `!`. + UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false).unwrap(), + }; + if do_panic { + let msg_str = if layout.abi.is_uninhabited() { + // Use this error even for the other intrinsics as it is more precise. + format!("attempted to instantiate uninhabited type `{}`", ty) + } else if intrinsic == ZeroValid { + format!("attempted to zero-initialize type `{}`, which is invalid", ty) + } else { + format!("attempted to leave type `{}` uninitialized, which is invalid", ty) + }; + let msg = bx.const_str(Symbol::intern(&msg_str)); + let location = self.get_caller_location(bx, span).immediate(); + + // Obtain the panic entry point. + // FIXME: dedup this with `codegen_assert_terminator` above. + let def_id = + common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); + let instance = ty::Instance::mono(bx.tcx(), def_id); + let fn_abi = FnAbi::of_instance(bx, instance, &[]); + let llfn = bx.get_fn_addr(instance); + + if let Some((_, target)) = destination.as_ref() { + helper.maybe_sideeffect(self.mir, bx, &[*target]); + } + // Codegen the actual panic invoke/call. + helper.do_call( + self, + bx, + fn_abi, + llfn, + &[msg.0, msg.1, location], + destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)), + cleanup, + ); + } else { + // a NOP + let target = destination.as_ref().unwrap().1; + helper.maybe_sideeffect(self.mir, bx, &[target]); + helper.funclet_br(self, bx, target) + } + true + } else { + false + } + } + fn codegen_call_terminator( &mut self, helper: TerminatorCodegenHelper<'tcx>, @@ -545,49 +627,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - // For normal codegen, this Miri-specific intrinsic is just a NOP. + // For normal codegen, this Miri-specific intrinsic should never occur. if intrinsic == Some("miri_start_panic") { - let target = destination.as_ref().unwrap().1; - helper.maybe_sideeffect(self.mir, &mut bx, &[target]); - helper.funclet_br(self, &mut bx, target); - return; + bug!("`miri_start_panic` should never end up in compiled code"); } - // Emit a panic or a no-op for `panic_if_uninhabited`. - if intrinsic == Some("panic_if_uninhabited") { - let ty = instance.unwrap().substs.type_at(0); - let layout = bx.layout_of(ty); - if layout.abi.is_uninhabited() { - let msg_str = format!("Attempted to instantiate uninhabited type {}", ty); - let msg = bx.const_str(Symbol::intern(&msg_str)); - let location = self.get_caller_location(&mut bx, span).immediate(); - - // Obtain the panic entry point. - let def_id = - common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); - let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_abi = FnAbi::of_instance(&bx, instance, &[]); - let llfn = bx.get_fn_addr(instance); - - if let Some((_, target)) = destination.as_ref() { - helper.maybe_sideeffect(self.mir, &mut bx, &[*target]); - } - // Codegen the actual panic invoke/call. - helper.do_call( - self, - &mut bx, - fn_abi, - llfn, - &[msg.0, msg.1, location], - destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)), - cleanup, - ); - } else { - // a NOP - let target = destination.as_ref().unwrap().1; - helper.maybe_sideeffect(self.mir, &mut bx, &[target]); - helper.funclet_br(self, &mut bx, target) - } + if self.codegen_panic_intrinsic( + &helper, + &mut bx, + intrinsic, + instance, + span, + destination, + cleanup, + ) { return; } @@ -1043,7 +1096,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { caller.line as u32, caller.col_display as u32 + 1, )); - OperandRef::from_const(bx, const_loc) + OperandRef::from_const(bx, const_loc, bx.tcx().caller_location_ty()) }) } diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 3ce916d7812..4248627dcca 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -1,7 +1,7 @@ use crate::mir::operand::OperandRef; use crate::traits::*; use rustc::mir; -use rustc::mir::interpret::ErrorHandled; +use rustc::mir::interpret::{ConstValue, ErrorHandled}; use rustc::ty::layout::{self, HasTyCtxt}; use rustc::ty::{self, Ty}; use rustc_index::vec::Idx; @@ -30,7 +30,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } _ => { let val = self.eval_mir_constant(constant)?; - Ok(OperandRef::from_const(bx, val)) + let ty = self.monomorphize(&constant.literal.ty); + Ok(OperandRef::from_const(bx, val, ty)) } } } @@ -38,7 +39,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn eval_mir_constant( &mut self, constant: &mir::Constant<'tcx>, - ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> { + ) -> Result, ErrorHandled> { match constant.literal.val { ty::ConstKind::Unevaluated(def_id, substs, promoted) => { let substs = self.monomorphize(&substs); @@ -55,7 +56,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { err }) } - _ => Ok(self.monomorphize(&constant.literal)), + ty::ConstKind::Value(value) => Ok(value), + _ => { + let const_ = self.monomorphize(&constant.literal); + if let ty::ConstKind::Value(value) = const_.val { + Ok(value) + } else { + span_bug!(constant.span, "encountered bad ConstKind in codegen: {:?}", const_); + } + } } } @@ -65,21 +74,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &Bx, span: Span, ty: Ty<'tcx>, - constant: Result<&'tcx ty::Const<'tcx>, ErrorHandled>, + constant: Result, ErrorHandled>, ) -> (Bx::Value, Ty<'tcx>) { constant - .map(|c| { - let field_ty = c.ty.builtin_index().unwrap(); - let fields = match c.ty.kind { + .map(|val| { + let field_ty = ty.builtin_index().unwrap(); + let fields = match ty.kind { ty::Array(_, n) => n.eval_usize(bx.tcx(), ty::ParamEnv::reveal_all()), - _ => bug!("invalid simd shuffle type: {}", c.ty), + _ => bug!("invalid simd shuffle type: {}", ty), }; + let c = ty::Const::from_value(bx.tcx(), val, ty); let values: Vec<_> = (0..fields) .map(|field| { let field = bx.tcx().const_field( ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize))), ); - if let Some(prim) = field.val.try_to_scalar() { + if let Some(prim) = field.try_to_scalar() { let layout = bx.layout_of(field_ty); let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/src/librustc_codegen_ssa/mir/debuginfo.rs index e5f21013ce3..cbe5f511152 100644 --- a/src/librustc_codegen_ssa/mir/debuginfo.rs +++ b/src/librustc_codegen_ssa/mir/debuginfo.rs @@ -1,10 +1,10 @@ use crate::traits::*; use rustc::mir; -use rustc::session::config::DebugInfo; use rustc::ty; use rustc::ty::layout::{LayoutOf, Size}; use rustc_hir::def_id::CrateNum; use rustc_index::vec::IndexVec; +use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; @@ -48,7 +48,7 @@ pub struct DebugScope { impl DebugScope { pub fn is_valid(&self) -> bool { - !self.scope_metadata.is_none() + self.scope_metadata.is_some() } } @@ -304,7 +304,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Option>>> { let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full; - if !(full_debug_info || !self.cx.sess().fewer_names()) { + if !full_debug_info && self.cx.sess().fewer_names() { return None; } diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index a33cd2ddad9..1e1fede2588 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -8,8 +8,8 @@ use crate::MemFlags; use rustc::mir; use rustc::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar}; -use rustc::ty; use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; +use rustc::ty::Ty; use std::fmt; @@ -66,20 +66,16 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { pub fn from_const>( bx: &mut Bx, - val: &'tcx ty::Const<'tcx>, + val: ConstValue<'tcx>, + ty: Ty<'tcx>, ) -> Self { - let layout = bx.layout_of(val.ty); + let layout = bx.layout_of(ty); if layout.is_zst() { return OperandRef::new_zst(bx, layout); } - let val_val = match val.val { - ty::ConstKind::Value(val_val) => val_val, - _ => bug!("encountered bad ConstKind in codegen"), - }; - - let val = match val_val { + let val = match val { ConstValue::Scalar(x) => { let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, @@ -96,8 +92,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let a = Scalar::from(Pointer::new( bx.tcx().alloc_map.lock().create_memory_alloc(data), Size::from_bytes(start as u64), - )) - .into(); + )); let a_llval = bx.scalar_to_backend( a, a_scalar, @@ -369,7 +364,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn maybe_codegen_consume_direct( &mut self, bx: &mut Bx, - place_ref: mir::PlaceRef<'_, 'tcx>, + place_ref: mir::PlaceRef<'tcx>, ) -> Option> { debug!("maybe_codegen_consume_direct(place_ref={:?})", place_ref); @@ -413,7 +408,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_consume( &mut self, bx: &mut Bx, - place_ref: mir::PlaceRef<'_, 'tcx>, + place_ref: mir::PlaceRef<'tcx>, ) -> OperandRef<'tcx, Bx::Value> { debug!("codegen_consume(place_ref={:?})", place_ref); diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index fa82daa0f7d..2eba88c6b5f 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -408,7 +408,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_place( &mut self, bx: &mut Bx, - place_ref: mir::PlaceRef<'_, 'tcx>, + place_ref: mir::PlaceRef<'tcx>, ) -> PlaceRef<'tcx, Bx::Value> { debug!("codegen_place(place_ref={:?})", place_ref); let cx = self.cx; @@ -497,7 +497,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { result } - pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'_, 'tcx>) -> Ty<'tcx> { + pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> { let tcx = self.cx.tcx(); let place_ty = mir::Place::ty_from(place_ref.local, place_ref.projection, *self.mir, tcx); self.monomorphize(&place_ty.ty) diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 2f83298741a..6d004606398 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -387,7 +387,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::AddressOf(mutability, ref place) => { let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| { - tcx.mk_ptr(ty::TypeAndMut { ty, mutbl: mutability.into() }) + tcx.mk_ptr(ty::TypeAndMut { ty, mutbl: mutability }) }; self.codegen_place_to_pointer(bx, place, mk_ptr) } diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs index 80d4b72fc53..536005f81e1 100644 --- a/src/librustc_codegen_ssa/traits/backend.rs +++ b/src/librustc_codegen_ssa/traits/backend.rs @@ -3,13 +3,13 @@ use super::CodegenObject; use crate::ModuleCodegen; use rustc::middle::cstore::EncodedMetadata; -use rustc::session::{config, Session}; use rustc::ty::layout::{HasTyCtxt, LayoutOf, TyLayout}; use rustc::ty::Ty; use rustc::ty::TyCtxt; +use rustc_ast::expand::allocator::AllocatorKind; use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_session::{config, Session}; use rustc_span::symbol::Symbol; -use syntax::expand::allocator::AllocatorKind; use std::sync::Arc; diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs index 56c3c29e10b..cf93c4af06b 100644 --- a/src/librustc_codegen_ssa/traits/debuginfo.rs +++ b/src/librustc_codegen_ssa/traits/debuginfo.rs @@ -3,10 +3,10 @@ use crate::mir::debuginfo::{FunctionDebugContext, VariableKind}; use rustc::mir; use rustc::ty::layout::Size; use rustc::ty::{Instance, Ty}; +use rustc_ast::ast::Name; use rustc_hir::def_id::CrateNum; use rustc_span::{SourceFile, Span}; use rustc_target::abi::call::FnAbi; -use syntax::ast::Name; pub trait DebugInfoMethods<'tcx>: BackendTypes { fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value); diff --git a/src/librustc_codegen_ssa/traits/misc.rs b/src/librustc_codegen_ssa/traits/misc.rs index fb1e01330ca..eb19cf83710 100644 --- a/src/librustc_codegen_ssa/traits/misc.rs +++ b/src/librustc_codegen_ssa/traits/misc.rs @@ -1,9 +1,9 @@ use super::BackendTypes; use rustc::mir::mono::CodegenUnit; -use rustc::session::Session; use rustc::sir::SirFuncCx; use rustc::ty::{self, Instance, Ty}; use rustc_data_structures::fx::FxHashMap; +use rustc_session::Session; use std::cell::RefCell; use std::sync::Arc; @@ -15,7 +15,6 @@ pub trait MiscMethods<'tcx>: BackendTypes { fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function; fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value; fn eh_personality(&self) -> Self::Value; - fn eh_unwind_resume(&self) -> Self::Value; fn sess(&self) -> &Session; fn codegen_unit(&self) -> &Arc>; fn used_statics(&self) -> &RefCell>; diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs index b8afadaadef..d03ff8d4d37 100644 --- a/src/librustc_codegen_ssa/traits/mod.rs +++ b/src/librustc_codegen_ssa/traits/mod.rs @@ -8,7 +8,7 @@ //! actual codegen, while the builder stores the information about the function during codegen and //! is used to produce the instructions of the backend IR. //! -//! Finaly, a third `Backend` structure has to implement methods related to how codegen information +//! Finally, a third `Backend` structure has to implement methods related to how codegen information //! is passed to the backend, especially for asynchronous compilation. //! //! The traits contain associated types that are backend-specific, such as the backend's value or diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index 8361a19ade9..7ab59029bc8 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -14,10 +14,11 @@ log = "0.4" punycode = "0.4.0" rustc-demangle = "0.1.16" -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } rustc = { path = "../librustc" } rustc_hir = { path = "../librustc_hir" } rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_metadata = { path = "../librustc_metadata" } +rustc_session = { path = "../librustc_session" } diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs index 96166e04c2e..561692e7066 100644 --- a/src/librustc_codegen_utils/codegen_backend.rs +++ b/src/librustc_codegen_utils/codegen_backend.rs @@ -10,11 +10,11 @@ use std::any::Any; use rustc::dep_graph::DepGraph; use rustc::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; -use rustc::session::config::{OutputFilenames, PrintRequest}; -use rustc::session::Session; use rustc::ty::query::Providers; use rustc::ty::TyCtxt; use rustc::util::common::ErrorReported; +use rustc_session::config::{OutputFilenames, PrintRequest}; +use rustc_session::Session; use rustc_span::symbol::Symbol; pub use rustc_data_structures::sync::MetadataRef; diff --git a/src/librustc_codegen_utils/link.rs b/src/librustc_codegen_utils/link.rs index 4dab4545b42..1f53eec514b 100644 --- a/src/librustc_codegen_utils/link.rs +++ b/src/librustc_codegen_utils/link.rs @@ -1,9 +1,9 @@ -use rustc::session::config::{self, Input, OutputFilenames, OutputType}; -use rustc::session::Session; +use rustc_ast::{ast, attr}; +use rustc_session::config::{self, Input, OutputFilenames, OutputType}; +use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Span; use std::path::{Path, PathBuf}; -use syntax::{ast, attr}; pub fn out_filename( sess: &Session, @@ -78,7 +78,7 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: } if let Input::File(ref path) = *input { if let Some(s) = path.file_stem().and_then(|s| s.to_str()) { - if s.starts_with("-") { + if s.starts_with('-') { let msg = format!( "crate names cannot start with a `-`, but \ `{}` has a leading hyphen", @@ -167,7 +167,9 @@ pub fn invalid_output_for_target(sess: &Session, crate_type: config::CrateType) if !sess.target.target.options.dynamic_linking { return true; } - if sess.crt_static() && !sess.target.target.options.crt_static_allows_dylibs { + if sess.crt_static(Some(crate_type)) + && !sess.target.target.options.crt_static_allows_dylibs + { return true; } } diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 6713459f627..eb3fe49a5e9 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -89,12 +89,12 @@ use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc::mir::mono::{InstantiationMode, MonoItem}; -use rustc::session::config::SymbolManglingVersion; use rustc::ty::query::Providers; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Instance, TyCtxt}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::Node; +use rustc_session::config::SymbolManglingVersion; use rustc_span::symbol::Symbol; @@ -185,7 +185,7 @@ fn compute_symbol_name( // // * On the wasm32 targets there is a bug (or feature) in LLD [1] where the // same-named symbol when imported from different wasm modules will get - // hooked up incorectly. As a result foreign symbols, on the wasm target, + // hooked up incorrectly. As a result foreign symbols, on the wasm target, // with a wasm import module, get mangled. Additionally our codegen will // deduplicate symbols based purely on the symbol name, but for wasm this // isn't quite right because the same-named symbol on wasm can come from diff --git a/src/librustc_codegen_utils/symbol_names/v0.rs b/src/librustc_codegen_utils/symbol_names/v0.rs index ff4e128e190..ce6d0d9dc5b 100644 --- a/src/librustc_codegen_utils/symbol_names/v0.rs +++ b/src/librustc_codegen_utils/symbol_names/v0.rs @@ -2,12 +2,12 @@ use rustc::hir::map::{DefPathData, DisambiguatedDefPathData}; use rustc::ty::print::{Print, Printer}; use rustc::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; +use rustc_ast::ast::{FloatTy, IntTy, UintTy}; use rustc_data_structures::base_n; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_target::spec::abi::Abi; -use syntax::ast::{FloatTy, IntTy, UintTy}; use std::fmt::Write; use std::ops::Range; diff --git a/src/librustc_data_structures/box_region.rs b/src/librustc_data_structures/box_region.rs index dbc54291f40..edeb4f83c7d 100644 --- a/src/librustc_data_structures/box_region.rs +++ b/src/librustc_data_structures/box_region.rs @@ -25,22 +25,6 @@ pub struct PinnedGenerator { } impl PinnedGenerator { - #[cfg(bootstrap)] - pub fn new, Return = R> + 'static>( - generator: T, - ) -> (I, Self) { - let mut result = PinnedGenerator { generator: Box::pin(generator) }; - - // Run it to the first yield to set it up - let init = match Pin::new(&mut result.generator).resume() { - GeneratorState::Yielded(YieldType::Initial(y)) => y, - _ => panic!(), - }; - - (init, result) - } - - #[cfg(not(bootstrap))] pub fn new, Return = R> + 'static>( generator: T, ) -> (I, Self) { @@ -55,19 +39,6 @@ impl PinnedGenerator { (init, result) } - #[cfg(bootstrap)] - pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) { - BOX_REGION_ARG.with(|i| { - i.set(Action::Access(AccessAction(closure))); - }); - - // Call the generator, which in turn will call the closure in BOX_REGION_ARG - if let GeneratorState::Complete(_) = Pin::new(&mut self.generator).resume() { - panic!() - } - } - - #[cfg(not(bootstrap))] pub unsafe fn access(&mut self, closure: *mut dyn FnMut()) { BOX_REGION_ARG.with(|i| { i.set(Action::Access(AccessAction(closure))); @@ -79,16 +50,6 @@ impl PinnedGenerator { } } - #[cfg(bootstrap)] - pub fn complete(&mut self) -> R { - // Tell the generator we want it to complete, consuming it and yielding a result - BOX_REGION_ARG.with(|i| i.set(Action::Complete)); - - let result = Pin::new(&mut self.generator).resume(); - if let GeneratorState::Complete(r) = result { r } else { panic!() } - } - - #[cfg(not(bootstrap))] pub fn complete(&mut self) -> R { // Tell the generator we want it to complete, consuming it and yielding a result BOX_REGION_ARG.with(|i| i.set(Action::Complete)); diff --git a/src/librustc_data_structures/frozen.rs b/src/librustc_data_structures/frozen.rs new file mode 100644 index 00000000000..2daf5b04141 --- /dev/null +++ b/src/librustc_data_structures/frozen.rs @@ -0,0 +1,63 @@ +//! An immutable, owned value (except for interior mutability). +//! +//! The purpose of `Frozen` is to make a value immutable for the sake of defensive programming. For example, +//! suppose we have the following: +//! +//! ```rust +//! struct Bar { /* some data */ } +//! +//! struct Foo { +//! /// Some computed data that should never change after construction. +//! pub computed: Bar, +//! +//! /* some other fields */ +//! } +//! +//! impl Bar { +//! /// Mutate the `Bar`. +//! pub fn mutate(&mut self) { } +//! } +//! ``` +//! +//! Now suppose we want to pass around a mutable `Foo` instance but, we want to make sure that +//! `computed` does not change accidentally (e.g. somebody might accidentally call +//! `foo.computed.mutate()`). This is what `Frozen` is for. We can do the following: +//! +//! ```rust +//! use rustc_data_structures::frozen::Frozen; +//! +//! struct Foo { +//! /// Some computed data that should never change after construction. +//! pub computed: Frozen, +//! +//! /* some other fields */ +//! } +//! ``` +//! +//! `Frozen` impls `Deref`, so we can ergonomically call methods on `Bar`, but it doesn't `impl +//! DerefMut`. Now calling `foo.compute.mutate()` will result in a compile-time error stating that +//! `mutate` requires a mutable reference but we don't have one. +//! +//! # Caveats +//! +//! - `Frozen` doesn't try to defend against interior mutability (e.g. `Frozen>`). +//! - `Frozen` doesn't pin it's contents (e.g. one could still do `foo.computed = +//! Frozen::freeze(new_bar)`). + +/// An owned immutable value. +#[derive(Debug)] +pub struct Frozen(T); + +impl Frozen { + pub fn freeze(val: T) -> Self { + Frozen(val) + } +} + +impl std::ops::Deref for Frozen { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index 70fc2d7dad9..7ecf3e3cb8d 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -97,7 +97,7 @@ impl GraphSuccessors<'graph> for Sccs { } impl WithSuccessors for Sccs { - fn successors<'graph>(&'graph self, node: S) -> >::Iter { + fn successors(&self, node: S) -> >::Iter { self.successors(node).iter().cloned() } } diff --git a/src/librustc_data_structures/graph/vec_graph/mod.rs b/src/librustc_data_structures/graph/vec_graph/mod.rs index 22c50afe6d0..064467174ca 100644 --- a/src/librustc_data_structures/graph/vec_graph/mod.rs +++ b/src/librustc_data_structures/graph/vec_graph/mod.rs @@ -101,7 +101,7 @@ impl GraphSuccessors<'graph> for VecGraph { } impl WithSuccessors for VecGraph { - fn successors<'graph>(&'graph self, node: N) -> >::Iter { + fn successors(&self, node: N) -> >::Iter { self.successors(node).iter().cloned() } } diff --git a/src/librustc_data_structures/graph/vec_graph/tests.rs b/src/librustc_data_structures/graph/vec_graph/tests.rs index 1db8bd4b102..c8f97926717 100644 --- a/src/librustc_data_structures/graph/vec_graph/tests.rs +++ b/src/librustc_data_structures/graph/vec_graph/tests.rs @@ -23,7 +23,7 @@ fn num_nodes() { } #[test] -fn succesors() { +fn successors() { let graph = create_graph(); assert_eq!(graph.successors(0), &[1]); assert_eq!(graph.successors(1), &[2, 3]); diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 13792a0c890..f9f8ff5303e 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -94,6 +94,7 @@ pub mod profiling; pub mod vec_linked_list; pub mod work_queue; pub use atomic_ref::AtomicRef; +pub mod frozen; pub struct OnDrop(pub F); diff --git a/src/librustc_data_structures/obligation_forest/graphviz.rs b/src/librustc_data_structures/obligation_forest/graphviz.rs index 0fd83dad56b..e1784f44fd1 100644 --- a/src/librustc_data_structures/obligation_forest/graphviz.rs +++ b/src/librustc_data_structures/obligation_forest/graphviz.rs @@ -52,7 +52,7 @@ impl<'a, O: ForestObligation + 'a> dot::Labeller<'a> for &'a ObligationForest fn node_label(&self, index: &Self::Node) -> dot::LabelText<'_> { let node = &self.nodes[*index]; - let label = format!("{:?} ({:?})", node.obligation.as_predicate(), node.state.get()); + let label = format!("{:?} ({:?})", node.obligation.as_cache_key(), node.state.get()); dot::LabelText::LabelStr(label.into()) } diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 0384776e9fb..6711a49b2b7 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -86,9 +86,13 @@ mod graphviz; mod tests; pub trait ForestObligation: Clone + Debug { - type Predicate: Clone + hash::Hash + Eq + Debug; + type CacheKey: Clone + hash::Hash + Eq + Debug; - fn as_predicate(&self) -> &Self::Predicate; + /// Converts this `ForestObligation` suitable for use as a cache key. + /// If two distinct `ForestObligations`s return the same cache key, + /// then it must be sound to use the result of processing one obligation + /// (e.g. success for error) for the other obligation + fn as_cache_key(&self) -> Self::CacheKey; } pub trait ObligationProcessor { @@ -138,12 +142,12 @@ pub struct ObligationForest { nodes: Vec>, /// A cache of predicates that have been successfully completed. - done_cache: FxHashSet, + done_cache: FxHashSet, /// A cache of the nodes in `nodes`, indexed by predicate. Unfortunately, /// its contents are not guaranteed to match those of `nodes`. See the /// comments in `process_obligation` for details. - active_cache: FxHashMap, + active_cache: FxHashMap, /// A vector reused in compress(), to avoid allocating new vectors. node_rewrites: Vec, @@ -157,7 +161,7 @@ pub struct ObligationForest { /// See [this][details] for details. /// /// [details]: https://github.com/rust-lang/rust/pull/53255#issuecomment-421184780 - error_cache: FxHashMap>, + error_cache: FxHashMap>, } #[derive(Debug)] @@ -305,11 +309,12 @@ impl ObligationForest { // Returns Err(()) if we already know this obligation failed. fn register_obligation_at(&mut self, obligation: O, parent: Option) -> Result<(), ()> { - if self.done_cache.contains(obligation.as_predicate()) { + if self.done_cache.contains(&obligation.as_cache_key()) { + debug!("register_obligation_at: ignoring already done obligation: {:?}", obligation); return Ok(()); } - match self.active_cache.entry(obligation.as_predicate().clone()) { + match self.active_cache.entry(obligation.as_cache_key()) { Entry::Occupied(o) => { let node = &mut self.nodes[*o.get()]; if let Some(parent_index) = parent { @@ -333,7 +338,7 @@ impl ObligationForest { && self .error_cache .get(&obligation_tree_id) - .map(|errors| errors.contains(obligation.as_predicate())) + .map(|errors| errors.contains(&obligation.as_cache_key())) .unwrap_or(false); if already_failed { @@ -380,7 +385,7 @@ impl ObligationForest { self.error_cache .entry(node.obligation_tree_id) .or_default() - .insert(node.obligation.as_predicate().clone()); + .insert(node.obligation.as_cache_key()); } /// Performs a pass through the obligation list. This must @@ -618,11 +623,11 @@ impl ObligationForest { // `self.nodes`. See the comment in `process_obligation` // for more details. if let Some((predicate, _)) = - self.active_cache.remove_entry(node.obligation.as_predicate()) + self.active_cache.remove_entry(&node.obligation.as_cache_key()) { self.done_cache.insert(predicate); } else { - self.done_cache.insert(node.obligation.as_predicate().clone()); + self.done_cache.insert(node.obligation.as_cache_key().clone()); } if do_completed == DoCompleted::Yes { // Extract the success stories. @@ -635,7 +640,7 @@ impl ObligationForest { // We *intentionally* remove the node from the cache at this point. Otherwise // tests must come up with a different type on every type error they // check against. - self.active_cache.remove(node.obligation.as_predicate()); + self.active_cache.remove(&node.obligation.as_cache_key()); self.insert_into_error_cache(index); node_rewrites[index] = orig_nodes_len; dead_nodes += 1; diff --git a/src/librustc_data_structures/obligation_forest/tests.rs b/src/librustc_data_structures/obligation_forest/tests.rs index e29335aab28..01652465eea 100644 --- a/src/librustc_data_structures/obligation_forest/tests.rs +++ b/src/librustc_data_structures/obligation_forest/tests.rs @@ -4,9 +4,9 @@ use std::fmt; use std::marker::PhantomData; impl<'a> super::ForestObligation for &'a str { - type Predicate = &'a str; + type CacheKey = &'a str; - fn as_predicate(&self) -> &Self::Predicate { + fn as_cache_key(&self) -> Self::CacheKey { self } } diff --git a/src/librustc_data_structures/profiling.rs b/src/librustc_data_structures/profiling.rs index debda9f0a0a..a70314c35c0 100644 --- a/src/librustc_data_structures/profiling.rs +++ b/src/librustc_data_structures/profiling.rs @@ -81,6 +81,7 @@ //! //! [mm]: https://github.com/rust-lang/measureme/ +use crate::cold_path; use crate::fx::FxHashMap; use std::borrow::Borrow; @@ -127,6 +128,7 @@ bitflags::bitflags! { const QUERY_KEYS = 1 << 5; const FUNCTION_ARGS = 1 << 6; + const LLVM = 1 << 7; const DEFAULT = Self::GENERIC_ACTIVITIES.bits | Self::QUERY_PROVIDERS.bits | @@ -150,6 +152,7 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[ ("query-keys", EventFilter::QUERY_KEYS), ("function-args", EventFilter::FUNCTION_ARGS), ("args", EventFilter::ARGS), + ("llvm", EventFilter::LLVM), ]; /// Something that uniquely identifies a query invocation. @@ -364,6 +367,15 @@ impl SelfProfilerRef { pub fn enabled(&self) -> bool { self.profiler.is_some() } + + #[inline] + pub fn llvm_recording_enabled(&self) -> bool { + self.event_filter_mask.contains(EventFilter::LLVM) + } + #[inline] + pub fn get_self_profiler(&self) -> Option> { + self.profiler.clone() + } } pub struct SelfProfiler { @@ -413,7 +425,7 @@ impl SelfProfiler { } // Warn about any unknown event names - if unknown_events.len() > 0 { + if !unknown_events.is_empty() { unknown_events.sort(); unknown_events.dedup(); @@ -520,9 +532,11 @@ impl<'a> TimingGuard<'a> { #[inline] pub fn finish_with_query_invocation_id(self, query_invocation_id: QueryInvocationId) { if let Some(guard) = self.0 { - let event_id = StringId::new_virtual(query_invocation_id.0); - let event_id = EventId::from_virtual(event_id); - guard.finish_with_override_event_id(event_id); + cold_path(|| { + let event_id = StringId::new_virtual(query_invocation_id.0); + let event_id = EventId::from_virtual(event_id); + guard.finish_with_override_event_id(event_id); + }); } } diff --git a/src/librustc_data_structures/sharded.rs b/src/librustc_data_structures/sharded.rs index ee3f88ff167..d08d46a7414 100644 --- a/src/librustc_data_structures/sharded.rs +++ b/src/librustc_data_structures/sharded.rs @@ -13,7 +13,7 @@ struct CacheAligned(T); #[cfg(parallel_compiler)] // 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700, // but this should be tested on higher core count CPUs. How the `Sharded` type gets used -// may also affect the ideal nunber of shards. +// may also affect the ideal number of shards. const SHARD_BITS: usize = 5; #[cfg(not(parallel_compiler))] @@ -41,7 +41,7 @@ impl Sharded { let mut values: SmallVec<[_; SHARDS]> = (0..SHARDS).map(|_| CacheAligned(Lock::new(value()))).collect(); - // Create an unintialized array + // Create an uninitialized array let mut shards: mem::MaybeUninit<[CacheAligned>; SHARDS]> = mem::MaybeUninit::uninit(); @@ -69,12 +69,21 @@ impl Sharded { /// `hash` can be computed with any hasher, so long as that hasher is used /// consistently for each `Sharded` instance. #[inline] - pub fn get_shard_by_hash(&self, hash: u64) -> &Lock { + pub fn get_shard_index_by_hash(&self, hash: u64) -> usize { let hash_len = mem::size_of::(); // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits. // hashbrown also uses the lowest bits, so we can't use those let bits = (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize; - let i = bits % SHARDS; + bits % SHARDS + } + + #[inline] + pub fn get_shard_by_hash(&self, hash: u64) -> &Lock { + &self.shards[self.get_shard_index_by_hash(hash)].0 + } + + #[inline] + pub fn get_shard_by_index(&self, i: usize) -> &Lock { &self.shards[i].0 } diff --git a/src/librustc_data_structures/sip128.rs b/src/librustc_data_structures/sip128.rs index 430f2f40caa..beb28dd0720 100644 --- a/src/librustc_data_structures/sip128.rs +++ b/src/librustc_data_structures/sip128.rs @@ -51,17 +51,48 @@ macro_rules! compress { }}; } -/// Loads up to 8 bytes from a byte-slice into a little-endian u64. -#[inline] -fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { - assert!(len <= 8 && start + len <= buf.len()); +/// Loads an integer of the desired type from a byte stream, in LE order. Uses +/// `copy_nonoverlapping` to let the compiler generate the most efficient way +/// to load it from a possibly unaligned address. +/// +/// Unsafe because: unchecked indexing at i..i+size_of(int_ty) +macro_rules! load_int_le { + ($buf:expr, $i:expr, $int_ty:ident) => {{ + debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len()); + let mut data = 0 as $int_ty; + ptr::copy_nonoverlapping( + $buf.get_unchecked($i), + &mut data as *mut _ as *mut u8, + mem::size_of::<$int_ty>(), + ); + data.to_le() + }}; +} - let mut out = 0u64; - unsafe { - let out_ptr = &mut out as *mut _ as *mut u8; - ptr::copy_nonoverlapping(buf.as_ptr().offset(start as isize), out_ptr, len); +/// Loads a u64 using up to 7 bytes of a byte slice. It looks clumsy but the +/// `copy_nonoverlapping` calls that occur (via `load_int_le!`) all have fixed +/// sizes and avoid calling `memcpy`, which is good for speed. +/// +/// Unsafe because: unchecked indexing at start..start+len +#[inline] +unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { + debug_assert!(len < 8); + let mut i = 0; // current byte index (from LSB) in the output u64 + let mut out = 0; + if i + 3 < len { + out = load_int_le!(buf, start + i, u32) as u64; + i += 4; + } + if i + 1 < len { + out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8); + i += 2 + } + if i < len { + out |= (*buf.get_unchecked(start + i) as u64) << (i * 8); + i += 1; } - out.to_le() + debug_assert_eq!(i, len); + out } impl SipHasher128 { @@ -243,7 +274,7 @@ impl Hasher for SipHasher128 { if self.ntail != 0 { needed = 8 - self.ntail; - self.tail |= u8to64_le(msg, 0, cmp::min(length, needed)) << (8 * self.ntail); + self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail); if length < needed { self.ntail += length; return; @@ -261,7 +292,7 @@ impl Hasher for SipHasher128 { let mut i = needed; while i < len - left { - let mi = u8to64_le(msg, i, 8); + let mi = unsafe { load_int_le!(msg, i, u64) }; self.state.v3 ^= mi; Sip24Rounds::c_rounds(&mut self.state); @@ -270,7 +301,7 @@ impl Hasher for SipHasher128 { i += 8; } - self.tail = u8to64_le(msg, i, left); + self.tail = unsafe { u8to64_le(msg, i, left) }; self.ntail = left; } diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index 08706aac11e..8c42b74b85a 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -4,6 +4,10 @@ use std::iter::FromIterator; use std::mem; use std::ops::{Bound, Index, IndexMut, RangeBounds}; +mod index_map; + +pub use index_map::SortedIndexMultiMap; + /// `SortedMap` is a data structure with similar characteristics as BTreeMap but /// slightly different trade-offs: lookup, insertion, and removal are O(log(N)) /// and elements can be iterated in order cheaply. diff --git a/src/librustc_data_structures/sorted_map/index_map.rs b/src/librustc_data_structures/sorted_map/index_map.rs new file mode 100644 index 00000000000..b7005ccdc99 --- /dev/null +++ b/src/librustc_data_structures/sorted_map/index_map.rs @@ -0,0 +1,218 @@ +//! A variant of `SortedMap` that preserves insertion order. + +use std::borrow::Borrow; +use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; + +use crate::stable_hasher::{HashStable, StableHasher}; +use rustc_index::vec::{Idx, IndexVec}; + +/// An indexed multi-map that preserves insertion order while permitting both `O(log n)` lookup of +/// an item by key and `O(1)` lookup by index. +/// +/// This data structure is a hybrid of an [`IndexVec`] and a [`SortedMap`]. Like `IndexVec`, +/// `SortedIndexMultiMap` assigns a typed index to each item while preserving insertion order. +/// Like `SortedMap`, `SortedIndexMultiMap` has efficient lookup of items by key. However, this +/// is accomplished by sorting an array of item indices instead of the items themselves. +/// +/// Unlike `SortedMap`, this data structure can hold multiple equivalent items at once, so the +/// `get_by_key` method and its variants return an iterator instead of an `Option`. Equivalent +/// items will be yielded in insertion order. +/// +/// Unlike a general-purpose map like `BTreeSet` or `HashSet`, `SortedMap` and +/// `SortedIndexMultiMap` require `O(n)` time to insert a single item. This is because we may need +/// to insert into the middle of the sorted array. Users should avoid mutating this data structure +/// in-place. +/// +/// [`IndexVec`]: ../../rustc_index/vec/struct.IndexVec.html +/// [`SortedMap`]: ../sorted_map/struct.SortedMap.html +#[derive(Clone, Debug)] +pub struct SortedIndexMultiMap { + /// The elements of the map in insertion order. + items: IndexVec, + + /// Indices of the items in the set, sorted by the item's key. + idx_sorted_by_item_key: Vec, +} + +impl SortedIndexMultiMap { + pub fn new() -> Self { + SortedIndexMultiMap { items: IndexVec::new(), idx_sorted_by_item_key: Vec::new() } + } + + pub fn len(&self) -> usize { + self.items.len() + } + + pub fn is_empty(&self) -> bool { + self.items.is_empty() + } + + /// Returns an iterator over the items in the map in insertion order. + pub fn into_iter(self) -> impl DoubleEndedIterator { + self.items.into_iter() + } + + /// Returns an iterator over the items in the map in insertion order along with their indices. + pub fn into_iter_enumerated(self) -> impl DoubleEndedIterator { + self.items.into_iter_enumerated() + } + + /// Returns an iterator over the items in the map in insertion order. + pub fn iter(&self) -> impl '_ + DoubleEndedIterator { + self.items.iter().map(|(ref k, ref v)| (k, v)) + } + + /// Returns an iterator over the items in the map in insertion order along with their indices. + pub fn iter_enumerated(&self) -> impl '_ + DoubleEndedIterator { + self.items.iter_enumerated().map(|(i, (ref k, ref v))| (i, (k, v))) + } + + /// Returns the item in the map with the given index. + pub fn get(&self, idx: I) -> Option<&(K, V)> { + self.items.get(idx) + } + + /// Returns an iterator over the items in the map that are equal to `key`. + /// + /// If there are multiple items that are equivalent to `key`, they will be yielded in + /// insertion order. + pub fn get_by_key(&'a self, key: &Q) -> impl 'a + Iterator + where + Q: Ord + ?Sized, + K: Borrow, + { + self.get_by_key_enumerated(key).map(|(_, v)| v) + } + + /// Returns an iterator over the items in the map that are equal to `key` along with their + /// indices. + /// + /// If there are multiple items that are equivalent to `key`, they will be yielded in + /// insertion order. + pub fn get_by_key_enumerated(&self, key: &Q) -> impl '_ + Iterator + where + Q: Ord + ?Sized, + K: Borrow, + { + // FIXME: This should be in the standard library as `equal_range`. See rust-lang/rfcs#2184. + match self.binary_search_idx(key) { + Err(_) => self.idxs_to_items_enumerated(&[]), + + Ok(idx) => { + let start = self.find_lower_bound(key, idx); + let end = self.find_upper_bound(key, idx); + self.idxs_to_items_enumerated(&self.idx_sorted_by_item_key[start..end]) + } + } + } + + fn binary_search_idx(&self, key: &Q) -> Result + where + Q: Ord + ?Sized, + K: Borrow, + { + self.idx_sorted_by_item_key.binary_search_by(|&idx| self.items[idx].0.borrow().cmp(key)) + } + + /// Returns the index into the `idx_sorted_by_item_key` array of the first item equal to + /// `key`. + /// + /// `initial` must be an index into that same array for an item that is equal to `key`. + fn find_lower_bound(&self, key: &Q, initial: usize) -> usize + where + Q: Ord + ?Sized, + K: Borrow, + { + debug_assert!(self.items[self.idx_sorted_by_item_key[initial]].0.borrow() == key); + + // FIXME: At present, this uses linear search, meaning lookup is only `O(log n)` if duplicate + // entries are rare. It would be better to start with a linear search for the common case but + // fall back to an exponential search if many duplicates are found. This applies to + // `upper_bound` as well. + let mut start = initial; + while start != 0 && self.items[self.idx_sorted_by_item_key[start - 1]].0.borrow() == key { + start -= 1; + } + + start + } + + /// Returns the index into the `idx_sorted_by_item_key` array of the first item greater than + /// `key`, or `self.len()` if no such item exists. + /// + /// `initial` must be an index into that same array for an item that is equal to `key`. + fn find_upper_bound(&self, key: &Q, initial: usize) -> usize + where + Q: Ord + ?Sized, + K: Borrow, + { + debug_assert!(self.items[self.idx_sorted_by_item_key[initial]].0.borrow() == key); + + // See the FIXME for `find_lower_bound`. + let mut end = initial + 1; + let len = self.items.len(); + while end < len && self.items[self.idx_sorted_by_item_key[end]].0.borrow() == key { + end += 1; + } + + end + } + + fn idxs_to_items_enumerated(&'a self, idxs: &'a [I]) -> impl 'a + Iterator { + idxs.iter().map(move |&idx| (idx, &self.items[idx].1)) + } +} + +impl Eq for SortedIndexMultiMap {} +impl PartialEq for SortedIndexMultiMap { + fn eq(&self, other: &Self) -> bool { + // No need to compare the sorted index. If the items are the same, the index will be too. + self.items == other.items + } +} + +impl Hash for SortedIndexMultiMap +where + K: Hash, + V: Hash, +{ + fn hash(&self, hasher: &mut H) { + self.items.hash(hasher) + } +} +impl HashStable for SortedIndexMultiMap +where + K: HashStable, + V: HashStable, +{ + fn hash_stable(&self, ctx: &mut C, hasher: &mut StableHasher) { + self.items.hash_stable(ctx, hasher) + } +} + +impl FromIterator<(K, V)> for SortedIndexMultiMap { + fn from_iter(iter: J) -> Self + where + J: IntoIterator, + { + let items = IndexVec::from_iter(iter); + let mut idx_sorted_by_item_key: Vec<_> = items.indices().collect(); + + // `sort_by_key` is stable, so insertion order is preserved for duplicate items. + idx_sorted_by_item_key.sort_by_key(|&idx| &items[idx].0); + + SortedIndexMultiMap { items, idx_sorted_by_item_key } + } +} + +impl std::ops::Index for SortedIndexMultiMap { + type Output = V; + + fn index(&self, idx: I) -> &Self::Output { + &self.items[idx].1 + } +} + +#[cfg(tests)] +mod tests; diff --git a/src/librustc_data_structures/sorted_map/tests.rs b/src/librustc_data_structures/sorted_map/tests.rs index 692e1deb4be..7d91e1fdcef 100644 --- a/src/librustc_data_structures/sorted_map/tests.rs +++ b/src/librustc_data_structures/sorted_map/tests.rs @@ -1,4 +1,30 @@ -use super::SortedMap; +use super::{SortedIndexMultiMap, SortedMap}; + +#[test] +fn test_sorted_index_multi_map() { + let entries: Vec<_> = vec![(2, 0), (1, 0), (2, 1), (3, 0), (2, 2)]; + let set: SortedIndexMultiMap = entries.iter().copied().collect(); + + // Insertion order is preserved. + assert!(entries.iter().map(|(ref k, ref v)| (k, v)).eq(set.iter())); + + // Indexing + for (i, expect) in entries.iter().enumerate() { + assert_eq!(set[i], expect.1); + } + + // `get_by_key` works. + assert_eq!(set.get_by_key(&3).copied().collect::>(), vec![0]); + assert!(set.get_by_key(&4).next().is_none()); + + // `get_by_key` returns items in insertion order. + let twos: Vec<_> = set.get_by_key_enumerated(&2).collect(); + let idxs: Vec = twos.iter().map(|(i, _)| *i).collect(); + let values: Vec = twos.iter().map(|(_, &v)| v).collect(); + + assert_eq!(idxs, vec![0, 2, 4]); + assert_eq!(values, vec![0, 1, 2]); +} #[test] fn test_insert_and_iter() { diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 0a26bf3bdc9..a98e77cebd8 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -27,6 +27,7 @@ pub trait StableHasherResult: Sized { } impl StableHasher { + #[inline] pub fn new() -> Self { StableHasher { state: SipHasher128::new_with_keys(0, 0) } } diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index fa98b4d72dd..9051b1751b1 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -203,11 +203,7 @@ cfg_if! { t.into_iter() } - pub fn par_for_each_in( - t: T, - for_each: - impl Fn(<::IntoIter as Iterator>::Item) + Sync + Send - ) { + pub fn par_for_each_in(t: T, for_each: impl Fn(T::Item) + Sync + Send) { // We catch panics here ensuring that all the loop iterations execute. // This makes behavior consistent with the parallel compiler. let mut panic = None; @@ -397,9 +393,7 @@ cfg_if! { pub fn par_for_each_in( t: T, - for_each: impl Fn( - <::Iter as ParallelIterator>::Item - ) + Sync + Send + for_each: impl Fn(T::Item) + Sync + Send, ) { t.into_par_iter().for_each(for_each) } diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 5b185f9a8b6..3e644958231 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -31,8 +31,9 @@ rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_error_codes = { path = "../librustc_error_codes" } rustc_interface = { path = "../librustc_interface" } rustc_serialize = { path = "../libserialize", package = "serialize" } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } +rustc_session = { path = "../librustc_session" } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] } diff --git a/src/librustc_driver/README.md b/src/librustc_driver/README.md index c4d73953e9b..37dc7f6ba5f 100644 --- a/src/librustc_driver/README.md +++ b/src/librustc_driver/README.md @@ -5,6 +5,6 @@ not contain any of the "main logic" of the compiler (though it does have some code related to pretty printing or other minor compiler options). -For more information about how the driver works, see the [rustc guide]. +For more information about how the driver works, see the [rustc dev guide]. -[rustc guide]: https://rust-lang.github.io/rustc-guide/rustc-driver.html +[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/rustc-driver.html diff --git a/src/librustc_driver/args.rs b/src/librustc_driver/args.rs index 5e2c43596db..5686819c61b 100644 --- a/src/librustc_driver/args.rs +++ b/src/librustc_driver/args.rs @@ -4,7 +4,7 @@ use std::fs; use std::io; pub fn arg_expand(arg: String) -> Result, Error> { - if arg.starts_with("@") { + if arg.starts_with('@') { let path = &arg[1..]; let file = match fs::read_to_string(path) { Ok(file) => file, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index f68ea7e0770..34f0c182499 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -18,19 +18,17 @@ extern crate lazy_static; pub extern crate rustc_plugin_impl as plugin; -use rustc::lint::{Lint, LintId}; use rustc::middle::cstore::MetadataLoader; -use rustc::session::config::nightly_options; -use rustc::session::config::{ErrorOutputType, Input, OutputType, PrintRequest}; -use rustc::session::{config, DiagnosticOutput, Session}; -use rustc::session::{early_error, early_warn}; use rustc::ty::TyCtxt; use rustc::util::common::ErrorReported; use rustc_codegen_ssa::CodegenResults; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_data_structures::profiling::print_time_passes_entry; use rustc_data_structures::sync::SeqCst; -use rustc_errors::{registry::Registry, PResult}; +use rustc_errors::{ + registry::{InvalidErrorCode, Registry}, + PResult, +}; use rustc_feature::{find_gated_cfg, UnstableFeatures}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::util::{collect_crate_types, get_builtin_codegen_backend}; @@ -40,6 +38,11 @@ use rustc_metadata::locator; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; use rustc_serialize::json::{self, ToJson}; +use rustc_session::config::nightly_options; +use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest}; +use rustc_session::lint::{Lint, LintId}; +use rustc_session::{config, DiagnosticOutput, Session}; +use rustc_session::{early_error, early_warn}; use std::borrow::Cow; use std::cmp::max; @@ -55,10 +58,10 @@ use std::process::{self, Command, Stdio}; use std::str; use std::time::Instant; +use rustc_ast::ast; use rustc_span::source_map::FileLoader; use rustc_span::symbol::sym; use rustc_span::FileName; -use syntax::ast; mod args; pub mod pretty; @@ -521,12 +524,11 @@ fn stdout_isatty() -> bool { fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) { let normalised = - if code.starts_with("E") { code.to_string() } else { format!("E{0:0>4}", code) }; - match registry.find_description(&normalised) { - Some(ref description) => { + if code.starts_with('E') { code.to_string() } else { format!("E{0:0>4}", code) }; + match registry.try_find_description(&normalised) { + Ok(Some(description)) => { let mut is_in_code_block = false; let mut text = String::new(); - // Slice off the leading newline and print. for line in description.lines() { let indent_level = @@ -542,16 +544,18 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) { } text.push('\n'); } - if stdout_isatty() { show_content_with_pager(&text); } else { print!("{}", text); } } - None => { + Ok(None) => { early_error(output, &format!("no extended information for {}", code)); } + Err(InvalidErrorCode) => { + early_error(output, &format!("{} is not a valid error code", code)); + } } } @@ -601,7 +605,7 @@ impl RustcDefaultCalls { }); compiler.codegen_backend().link(&sess, Box::new(codegen_results), &outputs) } else { - sess.fatal(&format!("rlink must be a file")) + sess.fatal("rlink must be a file") } } @@ -648,7 +652,7 @@ impl RustcDefaultCalls { odir: &Option, ofile: &Option, ) -> Compilation { - use rustc::session::config::PrintRequest::*; + use rustc_session::config::PrintRequest::*; // PrintRequest::NativeStaticLibs is special - printed during linking // (empty iterator returns true) if sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) { @@ -676,6 +680,10 @@ impl RustcDefaultCalls { println!("{}", targets.join("\n")); } Sysroot => println!("{}", sess.sysroot.display()), + TargetLibdir => println!( + "{}", + sess.target_tlib_path.as_ref().unwrap_or(&sess.host_tlib_path).dir.display() + ), TargetSpec => println!("{}", sess.target.target.to_json().pretty()), FileNames | CrateName => { let input = input.unwrap_or_else(|| { @@ -1116,12 +1124,7 @@ fn extra_compiler_flags() -> Option<(Vec, bool)> { return None; } - let matches = if let Some(matches) = handle_options(&args) { - matches - } else { - return None; - }; - + let matches = handle_options(&args)?; let mut result = Vec::new(); let mut excluded_cargo_defaults = false; for flag in ICE_REPORT_COMPILER_FLAGS { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index d4f01490499..1e5cc55a828 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -1,17 +1,17 @@ //! The various pretty-printing routines. use rustc::hir::map as hir_map; -use rustc::session::config::{Input, PpMode, PpSourceMode}; -use rustc::session::Session; use rustc::ty::{self, TyCtxt}; use rustc::util::common::ErrorReported; +use rustc_ast::ast; use rustc_ast_pretty::pprust; use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::print as pprust_hir; use rustc_mir::util::{write_mir_graphviz, write_mir_pretty}; +use rustc_session::config::{Input, PpMode, PpSourceMode}; +use rustc_session::Session; use rustc_span::FileName; -use syntax::ast; use std::cell::Cell; use std::fs::File; @@ -96,7 +96,7 @@ trait PrinterSupport: pprust::PpAnn { /// /// (Rust does not yet support upcasting from a trait object to /// an object for one of its super-traits.) - fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn; + fn pp_ann(&self) -> &dyn pprust::PpAnn; } trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { @@ -106,13 +106,13 @@ trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { /// Provides a uniform interface for re-extracting a reference to an /// `hir_map::Map` from a value that now owns it. - fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>>; + fn hir_map(&self) -> Option>; /// Produces the pretty-print annotation object. /// /// (Rust does not yet support upcasting from a trait object to /// an object for one of its super-traits.) - fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn; + fn pp_ann(&self) -> &dyn pprust_hir::PpAnn; /// Computes an user-readable representation of a path, if possible. fn node_path(&self, id: hir::HirId) -> Option { @@ -132,7 +132,7 @@ impl<'hir> PrinterSupport for NoAnn<'hir> { self.sess } - fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn { + fn pp_ann(&self) -> &dyn pprust::PpAnn { self } } @@ -142,11 +142,11 @@ impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { self.sess } - fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> { - self.tcx.map(|tcx| *tcx.hir()) + fn hir_map(&self) -> Option> { + self.tcx.map(|tcx| tcx.hir()) } - fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn { + fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { self } } @@ -155,7 +155,7 @@ impl<'hir> pprust::PpAnn for NoAnn<'hir> {} impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { if let Some(tcx) = self.tcx { - pprust_hir::PpAnn::nested(*tcx.hir(), state, nested) + pprust_hir::PpAnn::nested(&tcx.hir(), state, nested) } } } @@ -170,7 +170,7 @@ impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> { self.sess } - fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn { + fn pp_ann(&self) -> &dyn pprust::PpAnn { self } } @@ -216,11 +216,11 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { self.sess } - fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> { - self.tcx.map(|tcx| *tcx.hir()) + fn hir_map(&self) -> Option> { + self.tcx.map(|tcx| tcx.hir()) } - fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn { + fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { self } } @@ -228,7 +228,7 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { if let Some(ref tcx) = self.tcx { - pprust_hir::PpAnn::nested(*tcx.hir(), state, nested) + pprust_hir::PpAnn::nested(&tcx.hir(), state, nested) } } fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { @@ -315,11 +315,11 @@ impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> { &self.tcx.sess } - fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'tcx>> { - Some(&self.tcx.hir()) + fn hir_map(&self) -> Option> { + Some(self.tcx.hir()) } - fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn { + fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { self } @@ -334,7 +334,7 @@ impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { if let pprust_hir::Nested::Body(id) = nested { self.tables.set(self.tcx.body_tables(id)); } - pprust_hir::PpAnn::nested(*self.tcx.hir(), state, nested); + pprust_hir::PpAnn::nested(&self.tcx.hir(), state, nested); self.tables.set(old_tables); } fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { @@ -452,8 +452,8 @@ pub fn print_after_hir_lowering<'tcx>( call_with_pp_support_hir(&s, tcx, move |annotation, krate| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); - let cm = sess.source_map(); - *out = pprust_hir::print_crate(cm, krate, src_name, src, annotation.pp_ann()) + let sm = sess.source_map(); + *out = pprust_hir::print_crate(sm, krate, src_name, src, annotation.pp_ann()) }) } diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index ba43b29538d..85339ab9aa1 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -349,8 +349,10 @@ E0623: include_str!("./error_codes/E0623.md"), E0624: include_str!("./error_codes/E0624.md"), E0626: include_str!("./error_codes/E0626.md"), E0627: include_str!("./error_codes/E0627.md"), +E0628: include_str!("./error_codes/E0628.md"), E0631: include_str!("./error_codes/E0631.md"), E0633: include_str!("./error_codes/E0633.md"), +E0634: include_str!("./error_codes/E0634.md"), E0635: include_str!("./error_codes/E0635.md"), E0636: include_str!("./error_codes/E0636.md"), E0637: include_str!("./error_codes/E0637.md"), @@ -380,6 +382,7 @@ E0689: include_str!("./error_codes/E0689.md"), E0690: include_str!("./error_codes/E0690.md"), E0691: include_str!("./error_codes/E0691.md"), E0692: include_str!("./error_codes/E0692.md"), +E0693: include_str!("./error_codes/E0693.md"), E0695: include_str!("./error_codes/E0695.md"), E0697: include_str!("./error_codes/E0697.md"), E0698: include_str!("./error_codes/E0698.md"), @@ -395,6 +398,7 @@ E0714: include_str!("./error_codes/E0714.md"), E0715: include_str!("./error_codes/E0715.md"), E0716: include_str!("./error_codes/E0716.md"), E0718: include_str!("./error_codes/E0718.md"), +E0719: include_str!("./error_codes/E0719.md"), E0720: include_str!("./error_codes/E0720.md"), E0723: include_str!("./error_codes/E0723.md"), E0725: include_str!("./error_codes/E0725.md"), @@ -410,6 +414,7 @@ E0735: include_str!("./error_codes/E0735.md"), E0736: include_str!("./error_codes/E0736.md"), E0737: include_str!("./error_codes/E0737.md"), E0738: include_str!("./error_codes/E0738.md"), +E0739: include_str!("./error_codes/E0739.md"), E0740: include_str!("./error_codes/E0740.md"), E0741: include_str!("./error_codes/E0741.md"), E0742: include_str!("./error_codes/E0742.md"), @@ -417,6 +422,8 @@ E0743: include_str!("./error_codes/E0743.md"), E0744: include_str!("./error_codes/E0744.md"), E0745: include_str!("./error_codes/E0745.md"), E0746: include_str!("./error_codes/E0746.md"), +E0747: include_str!("./error_codes/E0747.md"), +E0748: include_str!("./error_codes/E0748.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard @@ -577,21 +584,18 @@ E0746: include_str!("./error_codes/E0746.md"), // E0612, // merged into E0609 // E0613, // Removed (merged with E0609) E0625, // thread-local statics cannot be accessed at compile-time - E0628, // generators cannot have explicit parameters E0629, // missing 'feature' (rustc_const_unstable) // rustc_const_unstable attribute must be paired with stable/unstable // attribute E0630, E0632, // cannot provide explicit generic arguments when `impl Trait` is // used in argument position - E0634, // type has conflicting packed representaton hints E0640, // infer outlives requirements // E0645, // trait aliases not finished E0657, // `impl Trait` can only capture lifetimes bound at the fn level E0667, // `impl Trait` in projections E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders - E0693, // incorrect `repr(align)` attribute format // E0694, // an unknown tool name found in scoped attributes E0696, // `continue` pointing to a labeled block // E0702, // replaced with a generic attribute input check @@ -603,10 +607,8 @@ E0746: include_str!("./error_codes/E0746.md"), E0710, // an unknown tool name found in scoped lint E0711, // a feature has been declared with conflicting stability attributes E0717, // rustc_promotable without stability attribute - E0719, // duplicate values for associated type binding // E0721, // `await` keyword E0722, // Malformed `#[optimize]` attribute E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions E0726, // non-explicit (not `'_`) elided lifetime in unsupported position - E0739, // invalid track_caller application/syntax } diff --git a/src/librustc_error_codes/error_codes/E0080.md b/src/librustc_error_codes/error_codes/E0080.md index 273238a943b..7b1bbde6140 100644 --- a/src/librustc_error_codes/error_codes/E0080.md +++ b/src/librustc_error_codes/error_codes/E0080.md @@ -14,7 +14,10 @@ constant expression that had to be evaluated. Attempting to divide by 0 or causing an integer overflow are two ways to induce this error. Ensure that the expressions given can be evaluated as the desired integer type. -See the FFI section of the Reference for more information about using a custom -integer type: -https://doc.rust-lang.org/reference.html#ffi-attributes +See the [Custom Discriminants][custom-discriminants] section of the Reference +for more information about setting custom integer types on fieldless enums +using the [`repr` attribute][repr-attribute]. + +[custom-discriminants]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations +[repr-attribute]: https://doc.rust-lang.org/reference/type-layout.html#reprc-enums diff --git a/src/librustc_error_codes/error_codes/E0117.md b/src/librustc_error_codes/error_codes/E0117.md index 7fa211d4a27..0544667ccca 100644 --- a/src/librustc_error_codes/error_codes/E0117.md +++ b/src/librustc_error_codes/error_codes/E0117.md @@ -1,4 +1,4 @@ -The `Drop` trait was implemented on a non-struct type. +Only traits defined in the current crate can be implemented for arbitrary types. Erroneous code example: diff --git a/src/librustc_error_codes/error_codes/E0133.md b/src/librustc_error_codes/error_codes/E0133.md index 0488cdd808d..1adbcc31356 100644 --- a/src/librustc_error_codes/error_codes/E0133.md +++ b/src/librustc_error_codes/error_codes/E0133.md @@ -28,4 +28,6 @@ fn main() { } ``` -See also https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html +See the [unsafe section][unsafe-section] of the Book for more details. + +[unsafe-section]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html diff --git a/src/librustc_error_codes/error_codes/E0154.md b/src/librustc_error_codes/error_codes/E0154.md index 725a775e72c..e437a71897c 100644 --- a/src/librustc_error_codes/error_codes/E0154.md +++ b/src/librustc_error_codes/error_codes/E0154.md @@ -27,7 +27,8 @@ fn f() { } ``` -See the Declaration Statements section of the reference for more information -about what constitutes an Item declaration and what does not: +See the [Declaration Statements][declaration-statements] section of the +reference for more information about what constitutes an item declaration +and what does not. -https://doc.rust-lang.org/reference.html#statements +[declaration-statements]: https://doc.rust-lang.org/reference/statements.html#declaration-statements diff --git a/src/librustc_error_codes/error_codes/E0260.md b/src/librustc_error_codes/error_codes/E0260.md index 4a36735ae76..b8bdb81fcbf 100644 --- a/src/librustc_error_codes/error_codes/E0260.md +++ b/src/librustc_error_codes/error_codes/E0260.md @@ -28,7 +28,8 @@ extern crate core as xyz; struct abc; ``` -See the Declaration Statements section of the reference for more information -about what constitutes an Item declaration and what does not: +See the [Declaration Statements][declaration-statements] section of the +reference for more information about what constitutes an item declaration +and what does not. -https://doc.rust-lang.org/reference.html#statements +[declaration-statements]: https://doc.rust-lang.org/reference/statements.html#declaration-statements diff --git a/src/librustc_error_codes/error_codes/E0303.md b/src/librustc_error_codes/error_codes/E0303.md index 700a66438e0..459906047cc 100644 --- a/src/librustc_error_codes/error_codes/E0303.md +++ b/src/librustc_error_codes/error_codes/E0303.md @@ -33,4 +33,6 @@ match Some("hi".to_string()) { The `op_string_ref` binding has type `&Option<&String>` in both cases. -See also https://github.com/rust-lang/rust/issues/14587 +See also [Issue 14587][issue-14587]. + +[issue-14587]: https://github.com/rust-lang/rust/issues/14587 diff --git a/src/librustc_error_codes/error_codes/E0308.md b/src/librustc_error_codes/error_codes/E0308.md index a907ca27297..7d87d54194e 100644 --- a/src/librustc_error_codes/error_codes/E0308.md +++ b/src/librustc_error_codes/error_codes/E0308.md @@ -1,10 +1,6 @@ -This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +Expected type did not match the received type. -For example: +Erroneous code example: ```compile_fail,E0308 let x: i32 = "I am not a number!"; @@ -15,3 +11,9 @@ let x: i32 = "I am not a number!"; // | // type `i32` assigned to variable `x` ``` + +This error occurs when the compiler was unable to infer the concrete type of a +variable. It can occur for several cases, the most common of which is a +mismatch in the expected type that the compiler inferred for a variable's +initializing expression, and the actual type explicitly assigned to the +variable. diff --git a/src/librustc_error_codes/error_codes/E0309.md b/src/librustc_error_codes/error_codes/E0309.md index 73ce7407476..e719ee590ab 100644 --- a/src/librustc_error_codes/error_codes/E0309.md +++ b/src/librustc_error_codes/error_codes/E0309.md @@ -1,9 +1,7 @@ -The type definition contains some field whose type -requires an outlives annotation. Outlives annotations -(e.g., `T: 'a`) are used to guarantee that all the data in T is valid -for at least the lifetime `'a`. This scenario most commonly -arises when the type contains an associated type reference -like `>::Output`, as shown in this example: +A parameter type is missing an explicit lifetime bound and may not live long +enough. + +Erroneous code example: ```compile_fail,E0309 // This won't compile because the applicable impl of @@ -25,9 +23,15 @@ where } ``` -Here, the where clause `T: 'a` that appears on the impl is not known to be -satisfied on the struct. To make this example compile, you have to add -a where-clause like `T: 'a` to the struct definition: +The type definition contains some field whose type requires an outlives +annotation. Outlives annotations (e.g., `T: 'a`) are used to guarantee that all +the data in T is valid for at least the lifetime `'a`. This scenario most +commonly arises when the type contains an associated type reference like +`>::Output`, as shown in the previous code. + +There, the where clause `T: 'a` that appears on the impl is not known to be +satisfied on the struct. To make this example compile, you have to add a +where-clause like `T: 'a` to the struct definition: ``` struct Foo<'a, T> diff --git a/src/librustc_error_codes/error_codes/E0310.md b/src/librustc_error_codes/error_codes/E0310.md index be87ccb114a..8d4311d018b 100644 --- a/src/librustc_error_codes/error_codes/E0310.md +++ b/src/librustc_error_codes/error_codes/E0310.md @@ -1,7 +1,7 @@ -Types in type definitions have lifetimes associated with them that represent -how long the data stored within them is guaranteed to be live. This lifetime -must be as long as the data needs to be alive, and missing the constraint that -denotes this will cause this error. +A parameter type is missing a lifetime constraint or has a lifetime that +does not live long enough. + +Erroneous code example: ```compile_fail,E0310 // This won't compile because T is not constrained to the static lifetime @@ -11,6 +11,11 @@ struct Foo { } ``` +Type parameters in type definitions have lifetimes associated with them that +represent how long the data stored within them is guaranteed to live. This +lifetime must be as long as the data needs to be alive, and missing the +constraint that denotes this will cause this error. + This will compile, because it has the constraint on the type parameter: ``` diff --git a/src/librustc_error_codes/error_codes/E0317.md b/src/librustc_error_codes/error_codes/E0317.md index e31a2b56be3..230911c2086 100644 --- a/src/librustc_error_codes/error_codes/E0317.md +++ b/src/librustc_error_codes/error_codes/E0317.md @@ -1,14 +1,30 @@ -This error occurs when an `if` expression without an `else` block is used in a -context where a type other than `()` is expected, for example a `let` -expression: +An `if` expression is missing an `else` block. + +Erroneous code example: ```compile_fail,E0317 -fn main() { - let x = 5; - let a = if x == 5 { 1 }; -} +let x = 5; +let a = if x == 5 { + 1 +}; ``` +This error occurs when an `if` expression without an `else` block is used in a +context where a type other than `()` is expected. In the previous code example, +the `let` expression was expecting a value but since there was no `else`, no +value was returned. + An `if` expression without an `else` block has the type `()`, so this is a type error. To resolve it, add an `else` block having the same type as the `if` block. + +So to fix the previous code example: + +``` +let x = 5; +let a = if x == 5 { + 1 +} else { + 2 +}; +``` diff --git a/src/librustc_error_codes/error_codes/E0321.md b/src/librustc_error_codes/error_codes/E0321.md index 49cec94430b..bfcdabfe9de 100644 --- a/src/librustc_error_codes/error_codes/E0321.md +++ b/src/librustc_error_codes/error_codes/E0321.md @@ -1,5 +1,7 @@ A cross-crate opt-out trait was implemented on something which wasn't a struct -or enum type. Erroneous code example: +or enum type. + +Erroneous code example: ```compile_fail,E0321 #![feature(optin_builtin_traits)] diff --git a/src/librustc_error_codes/error_codes/E0322.md b/src/librustc_error_codes/error_codes/E0322.md index d2ee426763e..ccef8681dd6 100644 --- a/src/librustc_error_codes/error_codes/E0322.md +++ b/src/librustc_error_codes/error_codes/E0322.md @@ -1,3 +1,13 @@ +The `Sized` trait was implemented explicitly. + +Erroneous code example: + +```compile_fail,E0322 +struct Foo; + +impl Sized for Foo {} // error! +``` + The `Sized` trait is a special trait built-in to the compiler for types with a constant size known at compile-time. This trait is automatically implemented for types as needed by the compiler, and it is currently disallowed to diff --git a/src/librustc_error_codes/error_codes/E0323.md b/src/librustc_error_codes/error_codes/E0323.md index 6d34c35f9cb..0bf42d17ebc 100644 --- a/src/librustc_error_codes/error_codes/E0323.md +++ b/src/librustc_error_codes/error_codes/E0323.md @@ -1,4 +1,5 @@ An associated const was implemented when another trait item was expected. + Erroneous code example: ```compile_fail,E0323 diff --git a/src/librustc_error_codes/error_codes/E0324.md b/src/librustc_error_codes/error_codes/E0324.md index b8c9e596990..1442cb77dd9 100644 --- a/src/librustc_error_codes/error_codes/E0324.md +++ b/src/librustc_error_codes/error_codes/E0324.md @@ -1,5 +1,6 @@ -A method was implemented when another trait item was expected. Erroneous -code example: +A method was implemented when another trait item was expected. + +Erroneous code example: ```compile_fail,E0324 struct Bar; diff --git a/src/librustc_error_codes/error_codes/E0325.md b/src/librustc_error_codes/error_codes/E0325.md index f685b92cbf0..656fd1ec82b 100644 --- a/src/librustc_error_codes/error_codes/E0325.md +++ b/src/librustc_error_codes/error_codes/E0325.md @@ -1,4 +1,5 @@ An associated type was implemented when another trait item was expected. + Erroneous code example: ```compile_fail,E0325 diff --git a/src/librustc_error_codes/error_codes/E0326.md b/src/librustc_error_codes/error_codes/E0326.md index 0702d00c2de..bc522e9cf40 100644 --- a/src/librustc_error_codes/error_codes/E0326.md +++ b/src/librustc_error_codes/error_codes/E0326.md @@ -1,7 +1,6 @@ -The types of any associated constants in a trait implementation must match the -types in the trait definition. This error indicates that there was a mismatch. +An implementation of a trait doesn't match the type constraint. -Here's an example of this error: +Erroneous code example: ```compile_fail,E0326 trait Foo { @@ -14,3 +13,6 @@ impl Foo for Bar { const BAR: u32 = 5; // error, expected bool, found u32 } ``` + +The types of any associated constants in a trait implementation must match the +types in the trait definition. diff --git a/src/librustc_error_codes/error_codes/E0364.md b/src/librustc_error_codes/error_codes/E0364.md index 0cca8f58b17..ec1fb911f3c 100644 --- a/src/librustc_error_codes/error_codes/E0364.md +++ b/src/librustc_error_codes/error_codes/E0364.md @@ -26,7 +26,7 @@ pub use foo::X; fn main() {} ``` -See the 'Use Declarations' section of the reference for more information on -this topic: +See the [Use Declarations][use-declarations] section of the reference for +more information on this topic. -https://doc.rust-lang.org/reference.html#use-declarations +[use-declarations]: https://doc.rust-lang.org/reference/items/use-declarations.html diff --git a/src/librustc_error_codes/error_codes/E0365.md b/src/librustc_error_codes/error_codes/E0365.md index 8f90d949e30..e3d417a7d01 100644 --- a/src/librustc_error_codes/error_codes/E0365.md +++ b/src/librustc_error_codes/error_codes/E0365.md @@ -26,7 +26,7 @@ pub use foo as foo2; fn main() {} ``` -See the 'Use Declarations' section of the reference for more information -on this topic: +See the [Use Declarations][use-declarations] section of the reference for +more information on this topic. -https://doc.rust-lang.org/reference.html#use-declarations +[use-declarations]: https://doc.rust-lang.org/reference/items/use-declarations.html diff --git a/src/librustc_error_codes/error_codes/E0367.md b/src/librustc_error_codes/error_codes/E0367.md index 7d661b2f033..cfebeada272 100644 --- a/src/librustc_error_codes/error_codes/E0367.md +++ b/src/librustc_error_codes/error_codes/E0367.md @@ -1,8 +1,9 @@ An attempt was made to implement `Drop` on a specialization of a generic type. -An example is shown below: + +Erroneous code example: ```compile_fail,E0367 -trait Foo{} +trait Foo {} struct MyStruct { t: T diff --git a/src/librustc_error_codes/error_codes/E0368.md b/src/librustc_error_codes/error_codes/E0368.md index 0bb283258c4..7b9d9334821 100644 --- a/src/librustc_error_codes/error_codes/E0368.md +++ b/src/librustc_error_codes/error_codes/E0368.md @@ -1,5 +1,7 @@ -This error indicates that a binary assignment operator like `+=` or `^=` was -applied to a type that doesn't support it. For example: +A binary assignment operator like `+=` or `^=` was applied to a type that +doesn't support it. + +Erroneous code example: ```compile_fail,E0368 let mut x = 12f32; // error: binary operation `<<` cannot be applied to diff --git a/src/librustc_error_codes/error_codes/E0369.md b/src/librustc_error_codes/error_codes/E0369.md index 397979e5641..ab0f4b40843 100644 --- a/src/librustc_error_codes/error_codes/E0369.md +++ b/src/librustc_error_codes/error_codes/E0369.md @@ -1,4 +1,5 @@ A binary operation was attempted on a type which doesn't support it. + Erroneous code example: ```compile_fail,E0369 diff --git a/src/librustc_error_codes/error_codes/E0370.md b/src/librustc_error_codes/error_codes/E0370.md index a3d280fc6dc..14e954722a2 100644 --- a/src/librustc_error_codes/error_codes/E0370.md +++ b/src/librustc_error_codes/error_codes/E0370.md @@ -1,5 +1,7 @@ The maximum value of an enum was reached, so it cannot be automatically -set in the next enum value. Erroneous code example: +set in the next enum value. + +Erroneous code example: ```compile_fail,E0370 #[repr(i64)] diff --git a/src/librustc_error_codes/error_codes/E0371.md b/src/librustc_error_codes/error_codes/E0371.md index 9363cddb1dd..a44721346e2 100644 --- a/src/librustc_error_codes/error_codes/E0371.md +++ b/src/librustc_error_codes/error_codes/E0371.md @@ -1,9 +1,6 @@ -When `Trait2` is a subtrait of `Trait1` (for example, when `Trait2` has a -definition like `trait Trait2: Trait1 { ... }`), it is not allowed to implement -`Trait1` for `Trait2`. This is because `Trait2` already implements `Trait1` by -definition, so it is not useful to do this. +A trait was implemented on another which already automatically implemented it. -Example: +Erroneous code examples: ```compile_fail,E0371 trait Foo { fn foo(&self) { } } @@ -15,3 +12,8 @@ impl Foo for Baz { } // error, `Baz` implements `Bar` which implements `Foo` impl Baz for Baz { } // error, `Baz` (trivially) implements `Baz` impl Baz for Bar { } // Note: This is OK ``` + +When `Trait2` is a subtrait of `Trait1` (for example, when `Trait2` has a +definition like `trait Trait2: Trait1 { ... }`), it is not allowed to implement +`Trait1` for `Trait2`. This is because `Trait2` already implements `Trait1` by +definition, so it is not useful to do this. diff --git a/src/librustc_error_codes/error_codes/E0373.md b/src/librustc_error_codes/error_codes/E0373.md index 808363e6eb0..fd969877931 100644 --- a/src/librustc_error_codes/error_codes/E0373.md +++ b/src/librustc_error_codes/error_codes/E0373.md @@ -1,6 +1,6 @@ -This error occurs when an attempt is made to use data captured by a closure, -when that data may no longer exist. It's most commonly seen when attempting to -return a closure: +A captured variable in a closure may not live long enough. + +Erroneous code example: ```compile_fail,E0373 fn foo() -> Box u32> { @@ -9,6 +9,10 @@ fn foo() -> Box u32> { } ``` +This error occurs when an attempt is made to use data captured by a closure, +when that data may no longer exist. It's most commonly seen when attempting to +return a closure as shown in the previous code example. + Notice that `x` is stack-allocated by `foo()`. By default, Rust captures closed-over data by reference. This means that once `foo()` returns, `x` no longer exists. An attempt to access `x` within the closure would thus be diff --git a/src/librustc_error_codes/error_codes/E0374.md b/src/librustc_error_codes/error_codes/E0374.md index 0e1a4bf8099..6d7dc88823c 100644 --- a/src/librustc_error_codes/error_codes/E0374.md +++ b/src/librustc_error_codes/error_codes/E0374.md @@ -1,9 +1,5 @@ -A struct without a field containing an unsized type cannot implement -`CoerceUnsized`. An [unsized type][1] is any type that the compiler -doesn't know the length or alignment of at compile time. Any struct -containing an unsized type is also unsized. - -[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait +`CoerceUnsized` was implemented on a struct which does not contain a field with +an unsized type. Example of erroneous code: @@ -20,6 +16,12 @@ impl CoerceUnsized> for Foo where T: CoerceUnsized {} ``` +An [unsized type][1] is any type where the compiler does not know the length or +alignment of at compile time. Any struct containing an unsized type is also +unsized. + +[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait + `CoerceUnsized` is used to coerce one struct containing an unsized type into another struct containing a different unsized type. If the struct doesn't have any fields of unsized types then you don't need explicit diff --git a/src/librustc_error_codes/error_codes/E0375.md b/src/librustc_error_codes/error_codes/E0375.md index 31fcd85cb07..71e53057165 100644 --- a/src/librustc_error_codes/error_codes/E0375.md +++ b/src/librustc_error_codes/error_codes/E0375.md @@ -1,12 +1,7 @@ -A struct with more than one field containing an unsized type cannot implement -`CoerceUnsized`. This only occurs when you are trying to coerce one of the -types in your struct to another type in the struct. In this case we try to -impl `CoerceUnsized` from `T` to `U` which are both types that the struct -takes. An [unsized type][1] is any type that the compiler doesn't know the -length or alignment of at compile time. Any struct containing an unsized type -is also unsized. +`CoerceUnsized` was implemented on a struct which contains more than one field +with an unsized type. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0375 #![feature(coerce_unsized)] @@ -22,6 +17,14 @@ struct Foo { impl CoerceUnsized> for Foo {} ``` +A struct with more than one field containing an unsized type cannot implement +`CoerceUnsized`. This only occurs when you are trying to coerce one of the +types in your struct to another type in the struct. In this case we try to +impl `CoerceUnsized` from `T` to `U` which are both types that the struct +takes. An [unsized type][1] is any type that the compiler doesn't know the +length or alignment of at compile time. Any struct containing an unsized type +is also unsized. + `CoerceUnsized` only allows for coercion from a structure with a single unsized type field to another struct with a single unsized type field. In fact Rust only allows for a struct to have one unsized type in a struct diff --git a/src/librustc_error_codes/error_codes/E0376.md b/src/librustc_error_codes/error_codes/E0376.md index b028aab4583..50de15bd30f 100644 --- a/src/librustc_error_codes/error_codes/E0376.md +++ b/src/librustc_error_codes/error_codes/E0376.md @@ -1,14 +1,6 @@ -The type you are trying to impl `CoerceUnsized` for is not a struct. -`CoerceUnsized` can only be implemented for a struct. Unsized types are -already able to be coerced without an implementation of `CoerceUnsized` -whereas a struct containing an unsized type needs to know the unsized type -field it's containing is able to be coerced. An [unsized type][1] -is any type that the compiler doesn't know the length or alignment of at -compile time. Any struct containing an unsized type is also unsized. - -[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait +`CoerceUnsized` was implemented on something that isn't a struct. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0376 #![feature(coerce_unsized)] @@ -22,6 +14,15 @@ struct Foo { impl CoerceUnsized for Foo {} ``` +`CoerceUnsized` can only be implemented for a struct. Unsized types are +already able to be coerced without an implementation of `CoerceUnsized` +whereas a struct containing an unsized type needs to know the unsized type +field it's containing is able to be coerced. An [unsized type][1] +is any type that the compiler doesn't know the length or alignment of at +compile time. Any struct containing an unsized type is also unsized. + +[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait + The `CoerceUnsized` trait takes a struct type. Make sure the type you are providing to `CoerceUnsized` is a struct with only the last field containing an unsized type. diff --git a/src/librustc_error_codes/error_codes/E0378.md b/src/librustc_error_codes/error_codes/E0378.md index 311483c8900..7f4374738de 100644 --- a/src/librustc_error_codes/error_codes/E0378.md +++ b/src/librustc_error_codes/error_codes/E0378.md @@ -1,10 +1,28 @@ +The `DispatchFromDyn` trait was implemented on something which is not a pointer +or a newtype wrapper around a pointer. + +Erroneous code example: + +```compile-fail,E0378 +#![feature(dispatch_from_dyn)] +use std::ops::DispatchFromDyn; + +struct WrapperExtraField { + ptr: T, + extra_stuff: i32, +} + +impl DispatchFromDyn> for WrapperExtraField +where + T: DispatchFromDyn, +{} +``` + The `DispatchFromDyn` trait currently can only be implemented for builtin pointer types and structs that are newtype wrappers around them — that is, the struct must have only one field (except for`PhantomData`), and that field must itself implement `DispatchFromDyn`. -Examples: - ``` #![feature(dispatch_from_dyn, unsize)] use std::{ @@ -20,6 +38,8 @@ where {} ``` +Another example: + ``` #![feature(dispatch_from_dyn)] use std::{ @@ -37,21 +57,3 @@ where T: DispatchFromDyn, {} ``` - -Example of illegal `DispatchFromDyn` implementation -(illegal because of extra field) - -```compile-fail,E0378 -#![feature(dispatch_from_dyn)] -use std::ops::DispatchFromDyn; - -struct WrapperExtraField { - ptr: T, - extra_stuff: i32, -} - -impl DispatchFromDyn> for WrapperExtraField -where - T: DispatchFromDyn, -{} -``` diff --git a/src/librustc_error_codes/error_codes/E0379.md b/src/librustc_error_codes/error_codes/E0379.md index 3503da6ac2f..930204847ec 100644 --- a/src/librustc_error_codes/error_codes/E0379.md +++ b/src/librustc_error_codes/error_codes/E0379.md @@ -1,3 +1,15 @@ +A trait method was declared const. + +Erroneous code example: + +```compile_fail,E0379 +#![feature(const_fn)] + +trait Foo { + const fn bar() -> u32; // error! +} +``` + Trait methods cannot be declared `const` by design. For more information, see [RFC 911]. diff --git a/src/librustc_error_codes/error_codes/E0380.md b/src/librustc_error_codes/error_codes/E0380.md index fe5de569339..638f0c8ecc6 100644 --- a/src/librustc_error_codes/error_codes/E0380.md +++ b/src/librustc_error_codes/error_codes/E0380.md @@ -1,4 +1,14 @@ -Auto traits cannot have methods or associated items. -For more information see the [opt-in builtin traits RFC][RFC 19]. +An auto trait was declared with a method or an associated item. + +Erroneous code example: + +```compile_fail,E0380 +unsafe auto trait Trait { + type Output; // error! +} +``` + +Auto traits cannot have methods or associated items. For more information see +the [opt-in builtin traits RFC][RFC 19]. [RFC 19]: https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md diff --git a/src/librustc_error_codes/error_codes/E0382.md b/src/librustc_error_codes/error_codes/E0382.md index 1592eac2ec5..d1408a06296 100644 --- a/src/librustc_error_codes/error_codes/E0382.md +++ b/src/librustc_error_codes/error_codes/E0382.md @@ -1,5 +1,4 @@ -This error occurs when an attempt is made to use a variable after its contents -have been moved elsewhere. +A variable was used after its contents have been moved elsewhere. Erroneous code example: @@ -104,7 +103,7 @@ With this approach, x and y share ownership of the data via the `Rc` (reference count type). `RefCell` essentially performs runtime borrow checking: ensuring that at most one writer or multiple readers can access the data at any one time. -If you wish to learn more about ownership in Rust, start with the chapter in the -Book: +If you wish to learn more about ownership in Rust, start with the +[Understanding Ownership][understanding-ownership] chapter in the Book. -https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html +[understanding-ownership]: https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html diff --git a/src/librustc_error_codes/error_codes/E0384.md b/src/librustc_error_codes/error_codes/E0384.md index 7c7ee744a8c..e21fac0797c 100644 --- a/src/librustc_error_codes/error_codes/E0384.md +++ b/src/librustc_error_codes/error_codes/E0384.md @@ -1,4 +1,4 @@ -This error occurs when an attempt is made to reassign an immutable variable. +An immutable variable was reassigned. Erroneous code example: diff --git a/src/librustc_error_codes/error_codes/E0387.md b/src/librustc_error_codes/error_codes/E0387.md index 3a5facfdd25..38ad19bd6aa 100644 --- a/src/librustc_error_codes/error_codes/E0387.md +++ b/src/librustc_error_codes/error_codes/E0387.md @@ -52,6 +52,6 @@ fn mutable() { } ``` -You can read more about cell types in the API documentation: +You can read more in the API documentation for [Cell][std-cell]. -https://doc.rust-lang.org/std/cell/ +[std-cell]: https://doc.rust-lang.org/std/cell/ diff --git a/src/librustc_error_codes/error_codes/E0390.md b/src/librustc_error_codes/error_codes/E0390.md index 9d05740d6f5..ecc5b5568ad 100644 --- a/src/librustc_error_codes/error_codes/E0390.md +++ b/src/librustc_error_codes/error_codes/E0390.md @@ -1,4 +1,6 @@ -You tried to implement methods for a primitive type. Erroneous code example: +A method was implemented on a primitive type. + +Erroneous code example: ```compile_fail,E0390 struct Foo { diff --git a/src/librustc_error_codes/error_codes/E0391.md b/src/librustc_error_codes/error_codes/E0391.md index 5db9ad16d08..dff50ccaa0b 100644 --- a/src/librustc_error_codes/error_codes/E0391.md +++ b/src/librustc_error_codes/error_codes/E0391.md @@ -1,7 +1,6 @@ -This error indicates that some types or traits depend on each other -and therefore cannot be constructed. +A type dependency cycle has been encountered. -The following example contains a circular dependency between two traits: +Erroneous code example: ```compile_fail,E0391 trait FirstTrait : SecondTrait { @@ -12,3 +11,6 @@ trait SecondTrait : FirstTrait { } ``` + +The previous example contains a circular dependency between two traits: +`FirstTrait` depends on `SecondTrait` which itself depends on `FirstTrait`. diff --git a/src/librustc_error_codes/error_codes/E0392.md b/src/librustc_error_codes/error_codes/E0392.md index 1d93e904e37..f373d89456d 100644 --- a/src/librustc_error_codes/error_codes/E0392.md +++ b/src/librustc_error_codes/error_codes/E0392.md @@ -1,5 +1,6 @@ -This error indicates that a type or lifetime parameter has been declared -but not actually used. Here is an example that demonstrates the error: +A type or lifetime parameter has been declared but is not actually used. + +Erroneous code example: ```compile_fail,E0392 enum Foo { diff --git a/src/librustc_error_codes/error_codes/E0393.md b/src/librustc_error_codes/error_codes/E0393.md index 7cce99401cf..3e853cf1b8a 100644 --- a/src/librustc_error_codes/error_codes/E0393.md +++ b/src/librustc_error_codes/error_codes/E0393.md @@ -1,5 +1,6 @@ A type parameter which references `Self` in its default value was not specified. -Example of erroneous code: + +Erroneous code example: ```compile_fail,E0393 trait A {} diff --git a/src/librustc_error_codes/error_codes/E0399.md b/src/librustc_error_codes/error_codes/E0399.md index 71482c3ca64..6ea6054b417 100644 --- a/src/librustc_error_codes/error_codes/E0399.md +++ b/src/librustc_error_codes/error_codes/E0399.md @@ -1,9 +1,11 @@ +#### Note: this error code is no longer emitted by the compiler + You implemented a trait, overriding one or more of its associated types but did not reimplement its default methods. Example of erroneous code: -```compile_fail,E0399 +``` #![feature(associated_type_defaults)] pub trait Foo { diff --git a/src/librustc_error_codes/error_codes/E0412.md b/src/librustc_error_codes/error_codes/E0412.md index 60a09610d86..d9ebc852bba 100644 --- a/src/librustc_error_codes/error_codes/E0412.md +++ b/src/librustc_error_codes/error_codes/E0412.md @@ -1,4 +1,4 @@ -The type name used is not in scope. +A used type name is not in scope. Erroneous code examples: diff --git a/src/librustc_error_codes/error_codes/E0422.md b/src/librustc_error_codes/error_codes/E0422.md index a91ea6a9e22..828a52e7341 100644 --- a/src/librustc_error_codes/error_codes/E0422.md +++ b/src/librustc_error_codes/error_codes/E0422.md @@ -1,4 +1,5 @@ -You are trying to use an identifier that is either undefined or not a struct. +An identifier that is neither defined nor a struct was used. + Erroneous code example: ```compile_fail,E0422 diff --git a/src/librustc_error_codes/error_codes/E0423.md b/src/librustc_error_codes/error_codes/E0423.md index 6a7c31f5e0d..a98ada17a46 100644 --- a/src/librustc_error_codes/error_codes/E0423.md +++ b/src/librustc_error_codes/error_codes/E0423.md @@ -1,8 +1,7 @@ An identifier was used like a function name or a value was expected and the identifier exists but it belongs to a different namespace. -For (an erroneous) example, here a `struct` variant name were used as a -function: +Erroneous code example: ```compile_fail,E0423 struct Foo { a: bool }; diff --git a/src/librustc_error_codes/error_codes/E0434.md b/src/librustc_error_codes/error_codes/E0434.md index e093f0796da..8fd60412baf 100644 --- a/src/librustc_error_codes/error_codes/E0434.md +++ b/src/librustc_error_codes/error_codes/E0434.md @@ -1,6 +1,4 @@ -This error indicates that a variable usage inside an inner function is invalid -because the variable comes from a dynamic environment. Inner functions do not -have access to their containing environment. +A variable used inside an inner function comes from a dynamic environment. Erroneous code example: @@ -14,8 +12,8 @@ fn foo() { } ``` -Functions do not capture local variables. To fix this error, you can replace the -function with a closure: +Inner functions do not have access to their containing environment. To fix this +error, you can replace the function with a closure: ``` fn foo() { @@ -26,7 +24,7 @@ fn foo() { } ``` -or replace the captured variable with a constant or a static item: +Or replace the captured variable with a constant or a static item: ``` fn foo() { diff --git a/src/librustc_error_codes/error_codes/E0455.md b/src/librustc_error_codes/error_codes/E0455.md index a642528dee2..2f80c34b889 100644 --- a/src/librustc_error_codes/error_codes/E0455.md +++ b/src/librustc_error_codes/error_codes/E0455.md @@ -15,5 +15,7 @@ To solve this error you can use conditional compilation: extern {} ``` -See more: -https://doc.rust-lang.org/reference/attributes.html#conditional-compilation +Learn more in the [Conditional Compilation][conditional-compilation] section +of the Reference. + +[conditional-compilation]: https://doc.rust-lang.org/reference/attributes.html#conditional-compilation diff --git a/src/librustc_error_codes/error_codes/E0499.md b/src/librustc_error_codes/error_codes/E0499.md index 370ceef530b..a07e8eb3b38 100644 --- a/src/librustc_error_codes/error_codes/E0499.md +++ b/src/librustc_error_codes/error_codes/E0499.md @@ -10,11 +10,13 @@ x; // error: cannot borrow `i` as mutable more than once at a time ``` -Please note that in rust, you can either have many immutable references, or one -mutable reference. Take a look at -https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html for more -information. Example: +Please note that in Rust, you can either have many immutable references, or one +mutable reference. For more details you may want to read the +[References & Borrowing][references-and-borrowing] section of the Book. +[references-and-borrowing]: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html + +Example: ``` let mut i = 0; diff --git a/src/librustc_error_codes/error_codes/E0501.md b/src/librustc_error_codes/error_codes/E0501.md index 95e0dfd4001..f5aa17a8094 100644 --- a/src/librustc_error_codes/error_codes/E0501.md +++ b/src/librustc_error_codes/error_codes/E0501.md @@ -3,9 +3,10 @@ captured by a closure. Because the closure has borrowed the variable, it is not available for use until the closure goes out of scope. Note that a capture will either move or borrow a variable, but in this -situation, the closure is borrowing the variable. Take a look at -http://rustbyexample.com/fn/closures/capture.html for more information about -capturing. +situation, the closure is borrowing the variable. Take a look at the chapter +on [Capturing][capturing] in Rust By Example for more information. + +[capturing]: https://doc.rust-lang.org/stable/rust-by-example/fn/closures/capture.html Erroneous code example: diff --git a/src/librustc_error_codes/error_codes/E0502.md b/src/librustc_error_codes/error_codes/E0502.md index 69220259e3d..f15c05d558d 100644 --- a/src/librustc_error_codes/error_codes/E0502.md +++ b/src/librustc_error_codes/error_codes/E0502.md @@ -25,5 +25,7 @@ fn foo(a: &mut i32) { } ``` -For more information on the rust ownership system, take a look at -https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html. +For more information on Rust's ownership system, take a look at the +[References & Borrowing][references-and-borrowing] section of the Book. + +[references-and-borrowing]: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html diff --git a/src/librustc_error_codes/error_codes/E0503.md b/src/librustc_error_codes/error_codes/E0503.md index c683619e3d0..c52525fee54 100644 --- a/src/librustc_error_codes/error_codes/E0503.md +++ b/src/librustc_error_codes/error_codes/E0503.md @@ -48,5 +48,7 @@ fn main() { } ``` -You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html +For more information on Rust's ownership system, take a look at the +[References & Borrowing][references-and-borrowing] section of the Book. + +[references-and-borrowing]: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html diff --git a/src/librustc_error_codes/error_codes/E0505.md b/src/librustc_error_codes/error_codes/E0505.md index 14baa01cb50..b11e3c0e947 100644 --- a/src/librustc_error_codes/error_codes/E0505.md +++ b/src/librustc_error_codes/error_codes/E0505.md @@ -81,5 +81,7 @@ fn main() { } ``` -You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html +For more information on Rust's ownership system, take a look at the +[References & Borrowing][references-and-borrowing] section of the Book. + +[references-and-borrowing]: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html diff --git a/src/librustc_error_codes/error_codes/E0507.md b/src/librustc_error_codes/error_codes/E0507.md index 89a6fb47377..1e3457e96c5 100644 --- a/src/librustc_error_codes/error_codes/E0507.md +++ b/src/librustc_error_codes/error_codes/E0507.md @@ -127,5 +127,7 @@ let borrowed = &mut cave; mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok! ``` -You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html +For more information on Rust's ownership system, take a look at the +[References & Borrowing][references-and-borrowing] section of the Book. + +[references-and-borrowing]: https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html diff --git a/src/librustc_error_codes/error_codes/E0525.md b/src/librustc_error_codes/error_codes/E0525.md index 95e5f362bde..a769440ca1b 100644 --- a/src/librustc_error_codes/error_codes/E0525.md +++ b/src/librustc_error_codes/error_codes/E0525.md @@ -36,5 +36,7 @@ fn main() { } ``` -To understand better how closures work in Rust, read: -https://doc.rust-lang.org/book/ch13-01-closures.html +To better understand how these work in Rust, read the [Closures][closures] +chapter of the Book. + +[closures]: https://doc.rust-lang.org/book/ch13-01-closures.html diff --git a/src/librustc_error_codes/error_codes/E0534.md b/src/librustc_error_codes/error_codes/E0534.md index 0afa4a8c958..1ca9411b8d4 100644 --- a/src/librustc_error_codes/error_codes/E0534.md +++ b/src/librustc_error_codes/error_codes/E0534.md @@ -31,5 +31,7 @@ compiler about inlining opportunity: fn something() {} ``` -For more information about the inline attribute, read: -https://doc.rust-lang.org/reference.html#inline-attributes +For more information see the [`inline` attribute][inline-attribute] section +of the Reference. + +[inline-attribute]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute diff --git a/src/librustc_error_codes/error_codes/E0535.md b/src/librustc_error_codes/error_codes/E0535.md index 035d395b76f..0cf3118b02c 100644 --- a/src/librustc_error_codes/error_codes/E0535.md +++ b/src/librustc_error_codes/error_codes/E0535.md @@ -24,5 +24,7 @@ pub fn something() {} fn main() {} ``` -For more information about the inline attribute, https: -read://doc.rust-lang.org/reference.html#inline-attributes +For more information see the [`inline` Attribute][inline-attribute] section +of the Reference. + +[inline-attribute]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute diff --git a/src/librustc_error_codes/error_codes/E0536.md b/src/librustc_error_codes/error_codes/E0536.md index 9006906a703..c081a3d9cfa 100644 --- a/src/librustc_error_codes/error_codes/E0536.md +++ b/src/librustc_error_codes/error_codes/E0536.md @@ -18,5 +18,7 @@ pub fn something() {} pub fn main() {} ``` -For more information about the cfg attribute, read: -https://doc.rust-lang.org/reference.html#conditional-compilation +For more information about the `cfg` attribute, read the section on +[Conditional Compilation][conditional-compilation] in the Reference. + +[conditional-compilation]: https://doc.rust-lang.org/reference/conditional-compilation.html diff --git a/src/librustc_error_codes/error_codes/E0537.md b/src/librustc_error_codes/error_codes/E0537.md index 82d8c6188af..123efd4f57d 100644 --- a/src/librustc_error_codes/error_codes/E0537.md +++ b/src/librustc_error_codes/error_codes/E0537.md @@ -24,5 +24,7 @@ pub fn something() {} pub fn main() {} ``` -For more information about the cfg attribute, read: -https://doc.rust-lang.org/reference.html#conditional-compilation +For more information about the `cfg` attribute, read the section on +[Conditional Compilation][conditional-compilation] in the Reference. + +[conditional-compilation]: https://doc.rust-lang.org/reference/conditional-compilation.html diff --git a/src/librustc_error_codes/error_codes/E0591.md b/src/librustc_error_codes/error_codes/E0591.md index 782d4cf29c3..7f68815b1c2 100644 --- a/src/librustc_error_codes/error_codes/E0591.md +++ b/src/librustc_error_codes/error_codes/E0591.md @@ -54,7 +54,7 @@ This pattern should be rewritten. There are a few possible ways to do this: - change the original fn declaration to match the expected signature, and do the cast in the fn body (the preferred option) -- cast the fn item fo a fn pointer before calling transmute, as shown here: +- cast the fn item of a fn pointer before calling transmute, as shown here: ``` # extern "C" fn foo(_: Box) {} diff --git a/src/librustc_error_codes/error_codes/E0601.md b/src/librustc_error_codes/error_codes/E0601.md index 12ae767c9e6..8180c5db46f 100644 --- a/src/librustc_error_codes/error_codes/E0601.md +++ b/src/librustc_error_codes/error_codes/E0601.md @@ -8,5 +8,7 @@ fn main() { } ``` -If you don't know the basics of Rust, you can go look to the Rust Book to get -started: https://doc.rust-lang.org/book/ +If you don't know the basics of Rust, you can look at the +[Rust Book][rust-book] to get started. + +[rust-book]: https://doc.rust-lang.org/book/ diff --git a/src/librustc_error_codes/error_codes/E0610.md b/src/librustc_error_codes/error_codes/E0610.md index d590ce51a33..c737bd618c3 100644 --- a/src/librustc_error_codes/error_codes/E0610.md +++ b/src/librustc_error_codes/error_codes/E0610.md @@ -24,6 +24,7 @@ let variable = Foo { x: 0, y: -12 }; println!("x: {}, y: {}", variable.x, variable.y); ``` -For more information about primitives and structs, take a look at The Book: -https://doc.rust-lang.org/book/ch03-02-data-types.html -https://doc.rust-lang.org/book/ch05-00-structs.html +For more information about [primitives] and [structs], take a look at the Book. + +[primitives]: https://doc.rust-lang.org/book/ch03-02-data-types.html +[structs]: https://doc.rust-lang.org/book/ch05-00-structs.html diff --git a/src/librustc_error_codes/error_codes/E0628.md b/src/librustc_error_codes/error_codes/E0628.md new file mode 100644 index 00000000000..40040c9a56a --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0628.md @@ -0,0 +1,30 @@ +More than one parameter was used for a generator. + +Erroneous code example: + +```compile_fail,E0628 +#![feature(generators, generator_trait)] + +fn main() { + let generator = |a: i32, b: i32| { + // error: too many parameters for a generator + // Allowed only 0 or 1 parameter + yield a; + }; +} +``` + +At present, it is not permitted to pass more than one explicit +parameter for a generator.This can be fixed by using +at most 1 parameter for the generator. For example, we might resolve +the previous example by passing only one parameter. + +``` +#![feature(generators, generator_trait)] + +fn main() { + let generator = |a: i32| { + yield a; + }; +} +``` diff --git a/src/librustc_error_codes/error_codes/E0634.md b/src/librustc_error_codes/error_codes/E0634.md new file mode 100644 index 00000000000..0c4ed2596e2 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0634.md @@ -0,0 +1,20 @@ +A type has conflicting `packed` representation hints. + +Erroneous code examples: + +```compile_fail,E0634 +#[repr(packed, packed(2))] // error! +struct Company(i32); + +#[repr(packed(2))] // error! +#[repr(packed)] +struct Company(i32); +``` + +You cannot use conflicting `packed` hints on a same type. If you want to pack a +type to a given size, you should provide a size to packed: + +``` +#[repr(packed)] // ok! +struct Company(i32); +``` diff --git a/src/librustc_error_codes/error_codes/E0660.md b/src/librustc_error_codes/error_codes/E0660.md index bceab1e0055..189459175dc 100644 --- a/src/librustc_error_codes/error_codes/E0660.md +++ b/src/librustc_error_codes/error_codes/E0660.md @@ -6,6 +6,7 @@ Erroneous code example: asm!("nop" "nop"); ``` -Considering that this would be a long explanation, we instead recommend you to -take a look at the unstable book: -https://doc.rust-lang.org/unstable-book/language-features/asm.html +Considering that this would be a long explanation, we instead recommend you +take a look at the [`asm`] chapter of the Unstable book: + +[asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/asm.html diff --git a/src/librustc_error_codes/error_codes/E0661.md b/src/librustc_error_codes/error_codes/E0661.md index 9979a61ee95..b171ada6205 100644 --- a/src/librustc_error_codes/error_codes/E0661.md +++ b/src/librustc_error_codes/error_codes/E0661.md @@ -7,6 +7,7 @@ let a; asm!("nop" : "r"(a)); ``` -Considering that this would be a long explanation, we instead recommend you to -take a look at the unstable book: -https://doc.rust-lang.org/unstable-book/language-features/asm.html +Considering that this would be a long explanation, we instead recommend you +take a look at the [`asm`] chapter of the Unstable book: + +[asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/asm.html diff --git a/src/librustc_error_codes/error_codes/E0662.md b/src/librustc_error_codes/error_codes/E0662.md index 3ba00eaab54..c15e736610b 100644 --- a/src/librustc_error_codes/error_codes/E0662.md +++ b/src/librustc_error_codes/error_codes/E0662.md @@ -9,6 +9,7 @@ asm!("xor %eax, %eax" ); ``` -Considering that this would be a long explanation, we instead recommend you to -take a look at the unstable book: -https://doc.rust-lang.org/unstable-book/language-features/asm.html +Considering that this would be a long explanation, we instead recommend you +take a look at the [`asm`] chapter of the Unstable book: + +[asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/asm.html diff --git a/src/librustc_error_codes/error_codes/E0663.md b/src/librustc_error_codes/error_codes/E0663.md index be121aa0b72..bd450230ec3 100644 --- a/src/librustc_error_codes/error_codes/E0663.md +++ b/src/librustc_error_codes/error_codes/E0663.md @@ -9,6 +9,7 @@ asm!("xor %eax, %eax" ); ``` -Considering that this would be a long explanation, we instead recommend you to -take a look at the unstable book: -https://doc.rust-lang.org/unstable-book/language-features/asm.html +Considering that this would be a long explanation, we instead recommend you +take a look at the [`asm`] chapter of the Unstable book: + +[asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/asm.html diff --git a/src/librustc_error_codes/error_codes/E0664.md b/src/librustc_error_codes/error_codes/E0664.md index 2b9546453d1..768ffdf2de9 100644 --- a/src/librustc_error_codes/error_codes/E0664.md +++ b/src/librustc_error_codes/error_codes/E0664.md @@ -10,6 +10,7 @@ asm!("mov $$0x200, %eax" ); ``` -Considering that this would be a long explanation, we instead recommend you to -take a look at the unstable book: -https://doc.rust-lang.org/unstable-book/language-features/asm.html +Considering that this would be a long explanation, we instead recommend you +take a look at the [`asm`] chapter of the Unstable book: + +[asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/asm.html diff --git a/src/librustc_error_codes/error_codes/E0693.md b/src/librustc_error_codes/error_codes/E0693.md new file mode 100644 index 00000000000..43e9d17979e --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0693.md @@ -0,0 +1,19 @@ +`align` representation hint was incorrectly declared. + +Erroneous code examples: + +```compile_fail,E0693 +#[repr(align=8)] // error! +struct Align8(i8); + +#[repr(align="8")] // error! +struct Align8(i8); +``` + +This is a syntax error at the level of attribute declarations. The proper +syntax for `align` representation hint is the following: + +``` +#[repr(align(8))] // ok! +struct Align8(i8); +``` diff --git a/src/librustc_error_codes/error_codes/E0719.md b/src/librustc_error_codes/error_codes/E0719.md new file mode 100644 index 00000000000..38bc63550ac --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0719.md @@ -0,0 +1,35 @@ +The value for an associated type has already been specified. + +Erroneous code example: + +```compile_fail,E0719 +#![feature(associated_type_bounds)] + +trait FooTrait {} +trait BarTrait {} + +// error: associated type `Item` in trait `Iterator` is specified twice +struct Foo> { f: T } +``` + +`Item` in trait `Iterator` cannot be specified multiple times for struct `Foo`. +To fix this, create a new trait that is a combination of the desired traits and +specify the associated type with the new trait. + +Corrected example: + +``` +#![feature(associated_type_bounds)] + +trait FooTrait {} +trait BarTrait {} +trait FooBarTrait: FooTrait + BarTrait {} + +struct Foo> { f: T } +``` + +For more information about associated types, see [the book][bk-at]. For more +information on associated type bounds, see [RFC 2289][rfc-2289]. + +[bk-at]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types +[rfc-2289]: https://rust-lang.github.io/rfcs/2289-associated-type-bounds.html diff --git a/src/librustc_error_codes/error_codes/E0739.md b/src/librustc_error_codes/error_codes/E0739.md new file mode 100644 index 00000000000..707751066ed --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0739.md @@ -0,0 +1,13 @@ +`#[track_caller]` can not be applied on struct. + +Erroneous code example: + +```compile_fail,E0739 +#![feature(track_caller)] +#[track_caller] +struct Bar { + a: u8, +} +``` + +[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md diff --git a/src/librustc_error_codes/error_codes/E0747.md b/src/librustc_error_codes/error_codes/E0747.md new file mode 100644 index 00000000000..df1afbfef46 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0747.md @@ -0,0 +1,20 @@ +Generic arguments must be provided in the same order as the corresponding +generic parameters are declared. + +Erroneous code example: + +```compile_fail,E0747 +struct S<'a, T>(&'a T); + +type X = S<(), 'static>; // error: the type argument is provided before the + // lifetime argument +``` + +The argument order should be changed to match the parameter declaration +order, as in the following. + +``` +struct S<'a, T>(&'a T); + +type X = S<'static, ()>; // ok +``` diff --git a/src/librustc_error_codes/error_codes/E0748.md b/src/librustc_error_codes/error_codes/E0748.md new file mode 100644 index 00000000000..69f1c026125 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0748.md @@ -0,0 +1,16 @@ +A raw string isn't correctly terminated because the trailing `#` count doesn't +match its leading `#` count. + +Erroneous code example: + +```compile_fail,E0748 +let dolphins = r##"Dolphins!"#; // error! +``` + +To terminate a raw string, you have to have the same number of `#` at the end +as at the beginning. Example: + +``` +let dolphins = r#"Dolphins!"#; // One `#` at the beginning, one at the end so + // all good! +``` diff --git a/src/librustc_error_codes/lib.rs b/src/librustc_error_codes/lib.rs index f051fdd11b8..4353a294cc3 100644 --- a/src/librustc_error_codes/lib.rs +++ b/src/librustc_error_codes/lib.rs @@ -3,8 +3,9 @@ macro_rules! register_diagnostics { ($($ecode:ident: $message:expr,)* ; $($code:ident,)*) => ( - pub static DIAGNOSTICS: &[(&str, &str)] = &[ - $( (stringify!($ecode), $message), )* + pub static DIAGNOSTICS: &[(&str, Option<&str>)] = &[ + $( (stringify!($ecode), Some($message)), )* + $( (stringify!($code), None), )* ]; ) } diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 189b5bd0f9e..1cc5daafed1 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -167,17 +167,17 @@ impl Diagnostic { found: DiagnosticStyledString, ) -> &mut Self { let mut msg: Vec<_> = - vec![(format!("required when trying to coerce from type `"), Style::NoStyle)]; + vec![("required when trying to coerce from type `".to_string(), Style::NoStyle)]; msg.extend(expected.0.iter().map(|x| match *x { StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), })); - msg.push((format!("` to type '"), Style::NoStyle)); + msg.push(("` to type '".to_string(), Style::NoStyle)); msg.extend(found.0.iter().map(|x| match *x { StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), })); - msg.push((format!("`"), Style::NoStyle)); + msg.push(("`".to_string(), Style::NoStyle)); // For now, just attach these as notes self.highlighted_note(msg); diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 39f585231ee..008d2e92418 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -136,12 +136,11 @@ impl<'a> DiagnosticBuilder<'a> { let handler = self.0.handler; - // We need to use `ptr::read` because `DiagnosticBuilder` implements `Drop`. - let diagnostic; - unsafe { - diagnostic = std::ptr::read(&self.0.diagnostic); - std::mem::forget(self); - }; + // We must use `Level::Cancelled` for `dummy` to avoid an ICE about an + // unused diagnostic. + let dummy = Diagnostic::new(Level::Cancelled, ""); + let diagnostic = std::mem::replace(&mut self.0.diagnostic, dummy); + // Logging here is useful to help track down where in logs an error was // actually emitted. debug!("buffer: diagnostic={:?}", diagnostic); diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index f3653da4be6..26f1fa267f9 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -5,7 +5,7 @@ //! There are various `Emitter` implementations that generate different output formats such as //! JSON and human readable output. //! -//! The output types are defined in `librustc::session::config::ErrorOutputType`. +//! The output types are defined in `rustc_session::config::ErrorOutputType`. use Destination::*; @@ -231,7 +231,7 @@ pub trait Emitter { ].contains(&sugg.style) { let substitution = &sugg.substitutions[0].parts[0].snippet.trim(); - let msg = if substitution.len() == 0 || sugg.style.hide_inline() { + let msg = if substitution.is_empty() || sugg.style.hide_inline() { // This substitution is only removal OR we explicitly don't want to show the // code inline (`hide_inline`). Therefore, we don't show the substitution. format!("help: {}", sugg.msg) @@ -414,22 +414,24 @@ pub trait Emitter { } // This does a small "fix" for multispans by looking to see if it can find any that - // point directly at <*macros>. Since these are often difficult to read, this - // will change the span to point at the use site. + // point directly at external macros. Since these are often difficult to read, + // this will change the span to point at the use site. fn fix_multispans_in_extern_macros( &self, source_map: &Option>, span: &mut MultiSpan, children: &mut Vec, ) { - for span in iter::once(span).chain(children.iter_mut().map(|child| &mut child.span)) { + debug!("fix_multispans_in_extern_macros: before: span={:?} children={:?}", span, children); + for span in iter::once(&mut *span).chain(children.iter_mut().map(|child| &mut child.span)) { self.fix_multispan_in_extern_macros(source_map, span); } + debug!("fix_multispans_in_extern_macros: after: span={:?} children={:?}", span, children); } - // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of - // <*macros>. Since these locations are often difficult to read, we move these Spans from - // <*macros> to their corresponding use site. + // This "fixes" MultiSpans that contain `Span`s pointing to locations inside of external macros. + // Since these locations are often difficult to read, + // we move these spans from the external macros to their corresponding use site. fn fix_multispan_in_extern_macros( &self, source_map: &Option>, @@ -440,14 +442,14 @@ pub trait Emitter { None => return, }; - // First, find all the spans in <*macros> and point instead at their use site + // First, find all the spans in external macros and point instead at their use site. let replacements: Vec<(Span, Span)> = span .primary_spans() .iter() .copied() .chain(span.span_labels().iter().map(|sp_label| sp_label.span)) .filter_map(|sp| { - if !sp.is_dummy() && sm.span_to_filename(sp).is_macros() { + if !sp.is_dummy() && sm.is_imported(sp) { let maybe_callsite = sp.source_callsite(); if sp != maybe_callsite { return Some((sp, maybe_callsite)); @@ -457,7 +459,7 @@ pub trait Emitter { }) .collect(); - // After we have them, make sure we replace these 'bad' def sites with their use sites + // After we have them, make sure we replace these 'bad' def sites with their use sites. for (from, to) in replacements { span.replace(from, to); } @@ -472,6 +474,7 @@ impl Emitter for EmitterWriter { fn emit_diagnostic(&mut self, diag: &Diagnostic) { let mut children = diag.children.clone(); let (mut primary_span, suggestions) = self.primary_span_formatted(&diag); + debug!("emit_diagnostic: suggestions={:?}", suggestions); self.fix_multispans_in_extern_macros_and_render_macro_backtrace( &self.sm, @@ -1533,6 +1536,7 @@ impl EmitterWriter { // Render the replacements for each suggestion let suggestions = suggestion.splice_lines(&**sm); + debug!("emit_suggestion_default: suggestions={:?}", suggestions); if suggestions.is_empty() { // Suggestions coming from macros can have malformed spans. This is a heavy handed @@ -1574,9 +1578,9 @@ impl EmitterWriter { let line_start = sm.lookup_char_pos(parts[0].span.lo()).line; draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1); - let mut line_pos = 0; let mut lines = complete.lines(); - for line in lines.by_ref().take(MAX_SUGGESTION_HIGHLIGHT_LINES) { + for (line_pos, line) in lines.by_ref().take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate() + { // Print the span column to avoid confusion buffer.puts( row_num, @@ -1587,7 +1591,6 @@ impl EmitterWriter { // print the suggestion draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); buffer.append(row_num, line, Style::NoStyle); - line_pos += 1; row_num += 1; } diff --git a/src/librustc_errors/json.rs b/src/librustc_errors/json.rs index ffdff6acec5..1382825922b 100644 --- a/src/librustc_errors/json.rs +++ b/src/librustc_errors/json.rs @@ -48,7 +48,7 @@ impl JsonEmitter { macro_backtrace: bool, ) -> JsonEmitter { JsonEmitter { - dst: Box::new(io::stderr()), + dst: Box::new(io::BufWriter::new(io::stderr())), registry, sm: source_map, pretty, @@ -104,7 +104,8 @@ impl Emitter for JsonEmitter { writeln!(&mut self.dst, "{}", as_pretty_json(&data)) } else { writeln!(&mut self.dst, "{}", as_json(&data)) - }; + } + .and_then(|_| self.dst.flush()); if let Err(e) = result { panic!("failed to print diagnostics: {:?}", e); } @@ -116,7 +117,8 @@ impl Emitter for JsonEmitter { writeln!(&mut self.dst, "{}", as_pretty_json(&data)) } else { writeln!(&mut self.dst, "{}", as_json(&data)) - }; + } + .and_then(|_| self.dst.flush()); if let Err(e) = result { panic!("failed to print notification: {:?}", e); } @@ -373,13 +375,13 @@ impl DiagnosticSpan { impl DiagnosticSpanLine { fn line_from_source_file( - fm: &rustc_span::SourceFile, + sf: &rustc_span::SourceFile, index: usize, h_start: usize, h_end: usize, ) -> DiagnosticSpanLine { DiagnosticSpanLine { - text: fm.get_line(index).map_or(String::new(), |l| l.into_owned()), + text: sf.get_line(index).map_or(String::new(), |l| l.into_owned()), highlight_start: h_start, highlight_end: h_end, } @@ -392,13 +394,18 @@ impl DiagnosticSpanLine { je.sm .span_to_lines(span) .map(|lines| { - let fm = &*lines.file; + // We can't get any lines if the source is unavailable. + if !je.sm.ensure_source_file_source_present(lines.file.clone()) { + return vec![]; + } + + let sf = &*lines.file; lines .lines .iter() .map(|line| { DiagnosticSpanLine::line_from_source_file( - fm, + sf, line.line_index, line.start_col.0 + 1, line.end_col.0 + 1, @@ -417,10 +424,10 @@ impl DiagnosticCode { DiagnosticId::Error(s) => s, DiagnosticId::Lint(s) => s, }; - let explanation = - je.registry.as_ref().and_then(|registry| registry.find_description(&s)); + let je_result = + je.registry.as_ref().map(|registry| registry.try_find_description(&s)).unwrap(); - DiagnosticCode { code: s, explanation } + DiagnosticCode { code: s, explanation: je_result.unwrap_or(None) } }) } } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 594e813def8..bed26c3736b 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -144,7 +144,7 @@ pub struct SubstitutionPart { impl CodeSuggestion { /// Returns the assembled code suggestions, whether they should be shown with an underline /// and whether the substitution only differs in capitalization. - pub fn splice_lines(&self, cm: &SourceMap) -> Vec<(String, Vec, bool)> { + pub fn splice_lines(&self, sm: &SourceMap) -> Vec<(String, Vec, bool)> { use rustc_span::{CharPos, Pos}; fn push_trailing( @@ -163,7 +163,7 @@ impl CodeSuggestion { None => buf.push_str(&line[lo..]), } } - if let None = hi_opt { + if hi_opt.is_none() { buf.push('\n'); } } @@ -176,7 +176,7 @@ impl CodeSuggestion { .filter(|subst| { // Suggestions coming from macros can have malformed spans. This is a heavy // handed approach to avoid ICEs by ignoring the suggestion outright. - let invalid = subst.parts.iter().any(|item| cm.is_valid_span(item.span).is_err()); + let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err()); if invalid { debug!("splice_lines: suggestion contains an invalid span: {:?}", subst); } @@ -193,9 +193,14 @@ impl CodeSuggestion { let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?; let bounding_span = Span::with_root_ctxt(lo, hi); // The different spans might belong to different contexts, if so ignore suggestion. - let lines = cm.span_to_lines(bounding_span).ok()?; + let lines = sm.span_to_lines(bounding_span).ok()?; assert!(!lines.lines.is_empty()); + // We can't splice anything if the source is unavailable. + if !sm.ensure_source_file_source_present(lines.file.clone()) { + return None; + } + // To build up the result, we do this for each span: // - push the line segment trailing the previous span // (at the beginning a "phantom" span pointing at the start of the line) @@ -205,36 +210,36 @@ impl CodeSuggestion { // - splice in the span substitution // // Finally push the trailing line segment of the last span - let fm = &lines.file; - let mut prev_hi = cm.lookup_char_pos(bounding_span.lo()); + let sf = &lines.file; + let mut prev_hi = sm.lookup_char_pos(bounding_span.lo()); prev_hi.col = CharPos::from_usize(0); - let mut prev_line = fm.get_line(lines.lines[0].line_index); + let mut prev_line = sf.get_line(lines.lines[0].line_index); let mut buf = String::new(); for part in &substitution.parts { - let cur_lo = cm.lookup_char_pos(part.span.lo()); + let cur_lo = sm.lookup_char_pos(part.span.lo()); if prev_hi.line == cur_lo.line { push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo)); } else { push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None); // push lines between the previous and current span (if any) for idx in prev_hi.line..(cur_lo.line - 1) { - if let Some(line) = fm.get_line(idx) { + if let Some(line) = sf.get_line(idx) { buf.push_str(line.as_ref()); buf.push('\n'); } } - if let Some(cur_line) = fm.get_line(cur_lo.line - 1) { + if let Some(cur_line) = sf.get_line(cur_lo.line - 1) { let end = std::cmp::min(cur_line.len(), cur_lo.col.to_usize()); buf.push_str(&cur_line[..end]); } } buf.push_str(&part.snippet); - prev_hi = cm.lookup_char_pos(part.span.hi()); - prev_line = fm.get_line(prev_hi.line - 1); + prev_hi = sm.lookup_char_pos(part.span.hi()); + prev_line = sf.get_line(prev_hi.line - 1); } - let only_capitalization = is_case_difference(cm, &buf, bounding_span); + let only_capitalization = is_case_difference(sm, &buf, bounding_span); // if the replacement already ends with a newline, don't print the next line if !buf.ends_with('\n') { push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None); @@ -363,23 +368,23 @@ impl Handler { color_config: ColorConfig, can_emit_warnings: bool, treat_err_as_bug: Option, - cm: Option>, + sm: Option>, ) -> Self { Self::with_tty_emitter_and_flags( color_config, - cm, + sm, HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() }, ) } pub fn with_tty_emitter_and_flags( color_config: ColorConfig, - cm: Option>, + sm: Option>, flags: HandlerFlags, ) -> Self { let emitter = Box::new(EmitterWriter::stderr( color_config, - cm, + sm, false, false, None, @@ -444,22 +449,12 @@ impl Handler { } /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing. - /// If the diagnostic with this `(span, key)` already exists, this will result in an ICE. pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { let mut inner = self.inner.borrow_mut(); - if let Some(mut old_diag) = inner.stashed_diagnostics.insert((span, key), diag) { - // We are removing a previously stashed diagnostic which should not happen. - old_diag.level = Bug; - old_diag.note(&format!( - "{}:{}: already existing stashed diagnostic with (span = {:?}, key = {:?})", - file!(), - line!(), - span, - key - )); - inner.emit_diag_at_span(old_diag, span); - panic!(ExplicitBug); - } + // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic + // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key. + // See the PR for a discussion. + inner.stashed_diagnostics.insert((span, key), diag); } /// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key. @@ -786,8 +781,12 @@ impl HandlerInner { .emitted_diagnostic_codes .iter() .filter_map(|x| match &x { - DiagnosticId::Error(s) if registry.find_description(s).is_some() => { - Some(s.clone()) + DiagnosticId::Error(s) => { + if let Ok(Some(_explanation)) = registry.try_find_description(s) { + Some(s.clone()) + } else { + None + } } _ => None, }) diff --git a/src/librustc_errors/registry.rs b/src/librustc_errors/registry.rs index 771542cb06f..32700c6500b 100644 --- a/src/librustc_errors/registry.rs +++ b/src/librustc_errors/registry.rs @@ -1,16 +1,32 @@ use rustc_data_structures::fx::FxHashMap; +#[derive(Debug)] +pub struct InvalidErrorCode; + #[derive(Clone)] pub struct Registry { - descriptions: FxHashMap<&'static str, &'static str>, + long_descriptions: FxHashMap<&'static str, Option<&'static str>>, } impl Registry { - pub fn new(descriptions: &[(&'static str, &'static str)]) -> Registry { - Registry { descriptions: descriptions.iter().cloned().collect() } + pub fn new(long_descriptions: &[(&'static str, Option<&'static str>)]) -> Registry { + Registry { long_descriptions: long_descriptions.iter().cloned().collect() } } + /// This will panic if an invalid error code is passed in pub fn find_description(&self, code: &str) -> Option<&'static str> { - self.descriptions.get(code).cloned() + self.try_find_description(code).unwrap() + } + /// Returns `InvalidErrorCode` if the code requested does not exist in the + /// registry. Otherwise, returns an `Option` where `None` means the error + /// code is valid but has no extended information. + pub fn try_find_description( + &self, + code: &str, + ) -> Result, InvalidErrorCode> { + if !self.long_descriptions.contains_key(code) { + return Err(InvalidErrorCode); + } + Ok(*self.long_descriptions.get(code).unwrap()) } } diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index a39e19f0bf7..0660590a725 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -152,7 +152,7 @@ impl Annotation { // | // // Note that this would be the complete output users would see. - label.len() > 0 + !label.is_empty() } else { false } diff --git a/src/librustc_expand/Cargo.toml b/src/librustc_expand/Cargo.toml index cb7919d630a..3cb79030771 100644 --- a/src/librustc_expand/Cargo.toml +++ b/src/librustc_expand/Cargo.toml @@ -24,4 +24,4 @@ rustc_lexer = { path = "../librustc_lexer" } rustc_parse = { path = "../librustc_parse" } rustc_session = { path = "../librustc_session" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index a5614f900b6..74c304c96b9 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -1,10 +1,17 @@ use crate::expand::{self, AstFragment, Invocation}; - +use crate::module::DirectoryOwnership; + +use rustc_ast::ast::{self, Attribute, Name, NodeId, PatKind}; +use rustc_ast::mut_visit::{self, MutVisitor}; +use rustc_ast::ptr::P; +use rustc_ast::token; +use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; +use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; -use rustc_parse::{self, parser, DirectoryOwnership, MACRO_ARGUMENTS}; +use rustc_parse::{self, parser, MACRO_ARGUMENTS}; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind}; @@ -12,12 +19,6 @@ use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{FileName, MultiSpan, Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; -use syntax::ast::{self, Attribute, Name, NodeId, PatKind}; -use syntax::mut_visit::{self, MutVisitor}; -use syntax::ptr::P; -use syntax::token; -use syntax::tokenstream::{self, TokenStream}; -use syntax::visit::{AssocCtxt, Visitor}; use std::default::Default; use std::iter; @@ -118,6 +119,31 @@ impl Annotatable { } } + crate fn into_tokens(self) -> TokenStream { + // `Annotatable` can be converted into tokens directly, but we + // are packing it into a nonterminal as a piece of AST to make + // the produced token stream look nicer in pretty-printed form. + let nt = match self { + Annotatable::Item(item) => token::NtItem(item), + Annotatable::TraitItem(item) | Annotatable::ImplItem(item) => { + token::NtItem(P(item.and_then(ast::AssocItem::into_item))) + } + Annotatable::ForeignItem(item) => { + token::NtItem(P(item.and_then(ast::ForeignItem::into_item))) + } + Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), + Annotatable::Expr(expr) => token::NtExpr(expr), + Annotatable::Arm(..) + | Annotatable::Field(..) + | Annotatable::FieldPat(..) + | Annotatable::GenericParam(..) + | Annotatable::Param(..) + | Annotatable::StructField(..) + | Annotatable::Variant(..) => panic!("unexpected annotatable"), + }; + TokenTree::token(token::Interpolated(Lrc::new(nt)), DUMMY_SP).into() + } + pub fn expect_item(self) -> P { match self { Annotatable::Item(i) => i, @@ -233,8 +259,17 @@ impl Annotatable { } } -// `meta_item` is the annotation, and `item` is the item being modified. -// FIXME Decorators should follow the same pattern too. +/// Result of an expansion that may need to be retried. +/// Consider using this for non-`MultiItemModifier` expanders as well. +pub enum ExpandResult { + /// Expansion produced a result (possibly dummy). + Ready(T), + /// Expansion could not produce a result and needs to be retried. + /// The string is an explanation that will be printed if we are stuck in an infinite retry loop. + Retry(U, String), +} + +// `meta_item` is the attribute, and `item` is the item being modified. pub trait MultiItemModifier { fn expand( &self, @@ -242,13 +277,12 @@ pub trait MultiItemModifier { span: Span, meta_item: &ast::MetaItem, item: Annotatable, - ) -> Vec; + ) -> ExpandResult, Annotatable>; } -impl MultiItemModifier for F +impl MultiItemModifier for F where - F: Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, Annotatable) -> T, - T: Into>, + F: Fn(&mut ExtCtxt<'_>, Span, &ast::MetaItem, Annotatable) -> Vec, { fn expand( &self, @@ -256,14 +290,8 @@ where span: Span, meta_item: &ast::MetaItem, item: Annotatable, - ) -> Vec { - (*self)(ecx, span, meta_item, item).into() - } -} - -impl Into> for Annotatable { - fn into(self) -> Vec { - vec![self] + ) -> ExpandResult, Annotatable> { + ExpandResult::Ready(self(ecx, span, meta_item, item)) } } @@ -347,7 +375,7 @@ where mut_visit::noop_visit_tt(tt, self) } - fn visit_mac(&mut self, mac: &mut ast::Mac) { + fn visit_mac(&mut self, mac: &mut ast::MacCall) { mut_visit::noop_visit_mac(mac, self) } } @@ -870,6 +898,7 @@ pub trait Resolver { fn has_derive_copy(&self, expn_id: ExpnId) -> bool; fn add_derive_copy(&mut self, expn_id: ExpnId); + fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result; } #[derive(Clone)] @@ -897,6 +926,8 @@ pub struct ExtCtxt<'a> { pub resolver: &'a mut dyn Resolver, pub current_expansion: ExpansionData, pub expansions: FxHashMap>, + /// Called directly after having parsed an external `mod foo;` in expansion. + pub(super) extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>, } impl<'a> ExtCtxt<'a> { @@ -904,12 +935,14 @@ impl<'a> ExtCtxt<'a> { parse_sess: &'a ParseSess, ecfg: expand::ExpansionConfig<'a>, resolver: &'a mut dyn Resolver, + extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>, ) -> ExtCtxt<'a> { ExtCtxt { parse_sess, ecfg, - root_path: PathBuf::new(), resolver, + extern_mod_loaded, + root_path: PathBuf::new(), current_expansion: ExpansionData { id: ExpnId::root(), depth: 0, diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs index af22e46eb6a..48ceaf5fccd 100644 --- a/src/librustc_expand/build.rs +++ b/src/librustc_expand/build.rs @@ -1,10 +1,10 @@ use crate::base::ExtCtxt; +use rustc_ast::ast::{self, AttrVec, BlockCheckMode, Expr, Ident, PatKind, UnOp}; +use rustc_ast::attr; +use rustc_ast::ptr::P; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Symbol}; -use syntax::ast::{self, AttrVec, BlockCheckMode, Expr, Ident, PatKind, UnOp}; -use syntax::attr; -use syntax::ptr::P; use rustc_span::Span; @@ -519,7 +519,7 @@ impl<'a> ExtCtxt<'a> { pub fn lambda(&self, span: Span, ids: Vec, body: P) -> P { let fn_decl = self.fn_decl( ids.iter().map(|id| self.param(span, *id, self.ty(span, ast::TyKind::Infer))).collect(), - ast::FunctionRetTy::Default(span), + ast::FnRetTy::Default(span), ); // FIXME -- We are using `span` as the span of the `|...|` @@ -569,7 +569,7 @@ impl<'a> ExtCtxt<'a> { } // FIXME: unused `self` - pub fn fn_decl(&self, inputs: Vec, output: ast::FunctionRetTy) -> P { + pub fn fn_decl(&self, inputs: Vec, output: ast::FnRetTy) -> P { P(ast::FnDecl { inputs, output }) } @@ -634,7 +634,7 @@ impl<'a> ExtCtxt<'a> { mutbl: ast::Mutability, expr: P, ) -> P { - self.item(span, name, Vec::new(), ast::ItemKind::Static(ty, mutbl, expr)) + self.item(span, name, Vec::new(), ast::ItemKind::Static(ty, mutbl, Some(expr))) } pub fn item_const( @@ -644,7 +644,8 @@ impl<'a> ExtCtxt<'a> { ty: P, expr: P, ) -> P { - self.item(span, name, Vec::new(), ast::ItemKind::Const(ty, expr)) + let def = ast::Defaultness::Final; + self.item(span, name, Vec::new(), ast::ItemKind::Const(def, ty, Some(expr))) } pub fn attribute(&self, mi: ast::MetaItem) -> ast::Attribute { diff --git a/src/librustc_parse/config.rs b/src/librustc_expand/config.rs similarity index 85% rename from src/librustc_parse/config.rs rename to src/librustc_expand/config.rs index 8dec64c579e..72c09f35dfa 100644 --- a/src/librustc_parse/config.rs +++ b/src/librustc_expand/config.rs @@ -1,14 +1,10 @@ -//! Process the potential `cfg` attributes on a module. -//! Also determine if the module should be included in this configuration. -//! -//! This module properly belongs in rustc_expand, but for now it's tied into -//! parsing, so we leave it here to avoid complicated out-of-line dependencies. -//! -//! A principled solution to this wrong location would be to implement [#64197]. -//! -//! [#64197]: https://github.com/rust-lang/rust/issues/64197 - -use crate::{parse_in, validate_attr}; +//! Conditional compilation stripping. + +use rustc_ast::ast::{self, AttrItem, Attribute, MetaItem}; +use rustc_ast::attr::HasAttrs; +use rustc_ast::mut_visit::*; +use rustc_ast::ptr::P; +use rustc_ast::util::map_in_place::MapInPlace; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{error_code, struct_span_err, Applicability, Handler}; @@ -16,15 +12,11 @@ use rustc_feature::{Feature, Features, State as FeatureState}; use rustc_feature::{ ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES, }; +use rustc_parse::{parse_in, validate_attr}; use rustc_session::parse::{feature_err, ParseSess}; use rustc_span::edition::{Edition, ALL_EDITIONS}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use syntax::ast::{self, AttrItem, Attribute, MetaItem}; -use syntax::attr::HasAttrs; -use syntax::mut_visit::*; -use syntax::ptr::P; -use syntax::util::map_in_place::MapInPlace; use smallvec::SmallVec; @@ -207,30 +199,29 @@ pub fn features( edition: Edition, allow_features: &Option>, ) -> (ast::Crate, Features) { - let features; - { - let mut strip_unconfigured = StripUnconfigured { sess, features: None }; + let mut strip_unconfigured = StripUnconfigured { sess, features: None }; - let unconfigured_attrs = krate.attrs.clone(); - let err_count = sess.span_diagnostic.err_count(); - if let Some(attrs) = strip_unconfigured.configure(krate.attrs) { - krate.attrs = attrs; - } else { - // the entire crate is unconfigured + let unconfigured_attrs = krate.attrs.clone(); + let diag = &sess.span_diagnostic; + let err_count = diag.err_count(); + let features = match strip_unconfigured.configure(krate.attrs) { + None => { + // The entire crate is unconfigured. krate.attrs = Vec::new(); krate.module.items = Vec::new(); - return (krate, Features::default()); + Features::default() } - - features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features); - - // Avoid reconfiguring malformed `cfg_attr`s - if err_count == sess.span_diagnostic.err_count() { - strip_unconfigured.features = Some(&features); - strip_unconfigured.configure(unconfigured_attrs); + Some(attrs) => { + krate.attrs = attrs; + let features = get_features(diag, &krate.attrs, edition, allow_features); + if err_count == diag.err_count() { + // Avoid reconfiguring malformed `cfg_attr`s. + strip_unconfigured.features = Some(&features); + strip_unconfigured.configure(unconfigured_attrs); + } + features } - } - + }; (krate, features) } @@ -258,7 +249,7 @@ impl<'a> StripUnconfigured<'a> { /// Parse and expand all `cfg_attr` attributes into a list of attributes /// that are within each `cfg_attr` that has a true configuration predicate. /// - /// Gives compiler warnigns if any `cfg_attr` does not contain any + /// Gives compiler warnings if any `cfg_attr` does not contain any /// attributes and is in the original source code. Gives compiler errors if /// the syntax of any `cfg_attr` is incorrect. pub fn process_cfg_attrs(&mut self, node: &mut T) { @@ -347,7 +338,13 @@ impl<'a> StripUnconfigured<'a> { if !is_cfg(attr) { return true; } - + let meta_item = match validate_attr::parse_meta(self.sess, attr) { + Ok(meta_item) => meta_item, + Err(mut err) => { + err.emit(); + return true; + } + }; let error = |span, msg, suggestion: &str| { let mut err = self.sess.span_diagnostic.struct_span_err(span, msg); if !suggestion.is_empty() { @@ -361,41 +358,15 @@ impl<'a> StripUnconfigured<'a> { err.emit(); true }; - - let meta_item = match validate_attr::parse_meta(self.sess, attr) { - Ok(meta_item) => meta_item, - Err(mut err) => { - err.emit(); - return true; - } - }; - let nested_meta_items = if let Some(nested_meta_items) = meta_item.meta_item_list() { - nested_meta_items - } else { - return error( - meta_item.span, - "`cfg` is not followed by parentheses", - "cfg(/* predicate */)", - ); - }; - - if nested_meta_items.is_empty() { - return error(meta_item.span, "`cfg` predicate is not specified", ""); - } else if nested_meta_items.len() > 1 { - return error( - nested_meta_items.last().unwrap().span(), - "multiple `cfg` predicates are specified", - "", - ); - } - - match nested_meta_items[0].meta_item() { - Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features), - None => error( - nested_meta_items[0].span(), - "`cfg` predicate key cannot be a literal", - "", - ), + let span = meta_item.span; + match meta_item.meta_item_list() { + None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"), + Some([]) => error(span, "`cfg` predicate is not specified", ""), + Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""), + Some([single]) => match single.meta_item() { + Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features), + None => error(single.span(), "`cfg` predicate key cannot be a literal", ""), + }, } }) } @@ -540,7 +511,7 @@ impl<'a> MutVisitor for StripUnconfigured<'a> { noop_flat_map_assoc_item(configure!(self, item), self) } - fn visit_mac(&mut self, _mac: &mut ast::Mac) { + fn visit_mac(&mut self, _mac: &mut ast::MacCall) { // Don't configure interpolated AST (cf. issue #34171). // Interpolated AST will get configured once the surrounding tokens are parsed. } @@ -559,17 +530,3 @@ impl<'a> MutVisitor for StripUnconfigured<'a> { fn is_cfg(attr: &Attribute) -> bool { attr.check_name(sym::cfg) } - -/// Process the potential `cfg` attributes on a module. -/// Also determine if the module should be included in this configuration. -pub fn process_configure_mod( - sess: &ParseSess, - cfg_mods: bool, - attrs: &[Attribute], -) -> (bool, Vec) { - // Don't perform gated feature checking. - let mut strip_unconfigured = StripUnconfigured { sess, features: None }; - let mut attrs = attrs.to_owned(); - strip_unconfigured.process_cfg_attrs(&mut attrs); - (!cfg_mods || strip_unconfigured.in_cfg(&attrs), attrs) -} diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 90692fe1ec9..b6cc192cc33 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -1,31 +1,32 @@ use crate::base::*; use crate::config::StripUnconfigured; +use crate::configure; use crate::hygiene::{ExpnData, ExpnId, ExpnKind, SyntaxContext}; use crate::mbe::macro_rules::annotate_err_with_kind; +use crate::module::{parse_external_mod, push_directory, Directory, DirectoryOwnership}; use crate::placeholders::{placeholder, PlaceholderExpander}; use crate::proc_macro::collect_derives; +use rustc_ast::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path}; +use rustc_ast::ast::{ItemKind, MacArgs, MacStmtStyle, StmtKind}; +use rustc_ast::mut_visit::*; +use rustc_ast::ptr::P; +use rustc_ast::token; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::util::map_in_place::MapInPlace; +use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; -use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::Features; -use rustc_parse::configure; use rustc_parse::parser::Parser; use rustc_parse::validate_attr; -use rustc_parse::DirectoryOwnership; +use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; +use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{FileName, Span, DUMMY_SP}; -use syntax::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path}; -use syntax::ast::{ItemKind, MacArgs, MacStmtStyle, StmtKind}; -use syntax::mut_visit::*; -use syntax::ptr::P; -use syntax::token; -use syntax::tokenstream::{TokenStream, TokenTree}; -use syntax::util::map_in_place::MapInPlace; -use syntax::visit::{self, AssocCtxt, Visitor}; use smallvec::{smallvec, SmallVec}; use std::io::ErrorKind; @@ -270,7 +271,7 @@ pub struct Invocation { pub enum InvocationKind { Bang { - mac: ast::Mac, + mac: ast::MacCall, span: Span, }, Attr { @@ -375,8 +376,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.span_err( span, &format!( - "expected crate top-level item to be a module after macro expansion, found a {}", - kind.descriptive_variant() + "expected crate top-level item to be a module after macro expansion, found {} {}", + kind.article(), kind.descr() ), ); } @@ -407,7 +408,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let mut undetermined_invocations = Vec::new(); let (mut progress, mut force) = (false, !self.monotonic); loop { - let invoc = if let Some(invoc) = invocations.pop() { + let (invoc, res) = if let Some(invoc) = invocations.pop() { invoc } else { self.resolve_imports(); @@ -419,30 +420,51 @@ impl<'a, 'b> MacroExpander<'a, 'b> { continue; }; - let eager_expansion_root = - if self.monotonic { invoc.expansion_data.id } else { orig_expansion_data.id }; - let res = match self.cx.resolver.resolve_macro_invocation( - &invoc, - eager_expansion_root, - force, - ) { - Ok(res) => res, - Err(Indeterminate) => { - undetermined_invocations.push(invoc); - continue; + let res = match res { + Some(res) => res, + None => { + let eager_expansion_root = if self.monotonic { + invoc.expansion_data.id + } else { + orig_expansion_data.id + }; + match self.cx.resolver.resolve_macro_invocation( + &invoc, + eager_expansion_root, + force, + ) { + Ok(res) => res, + Err(Indeterminate) => { + // Cannot resolve, will retry this invocation later. + undetermined_invocations.push((invoc, None)); + continue; + } + } } }; - progress = true; let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data; self.cx.current_expansion = invoc.expansion_data.clone(); // FIXME(jseyfried): Refactor out the following logic let (expanded_fragment, new_invocations) = match res { - InvocationRes::Single(ext) => { - let fragment = self.expand_invoc(invoc, &ext.kind); - self.collect_invocations(fragment, &[]) - } + InvocationRes::Single(ext) => match self.expand_invoc(invoc, &ext.kind) { + ExpandResult::Ready(fragment) => self.collect_invocations(fragment, &[]), + ExpandResult::Retry(invoc, explanation) => { + if force { + // We are stuck, stop retrying and produce a dummy fragment. + let span = invoc.span(); + self.cx.span_err(span, &explanation); + let fragment = invoc.fragment_kind.dummy(span); + self.collect_invocations(fragment, &[]) + } else { + // Cannot expand, will retry this invocation later. + undetermined_invocations + .push((invoc, Some(InvocationRes::Single(ext)))); + continue; + } + } + }, InvocationRes::DeriveContainer(_exts) => { // FIXME: Consider using the derive resolutions (`_exts`) immediately, // instead of enqueuing the derives to be resolved again later. @@ -451,28 +473,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => unreachable!(), }; if !item.derive_allowed() { - let attr = attr::find_by_name(item.attrs(), sym::derive) - .expect("`derive` attribute should exist"); - let span = attr.span; - let mut err = self.cx.struct_span_err( - span, - "`derive` may only be applied to structs, enums and unions", - ); - if let ast::AttrStyle::Inner = attr.style { - let trait_list = derives - .iter() - .map(|t| pprust::path_to_string(t)) - .collect::>(); - let suggestion = format!("#[derive({})]", trait_list.join(", ")); - err.span_suggestion( - span, - "try an outer attribute", - suggestion, - // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT - Applicability::MaybeIncorrect, - ); - } - err.emit(); + self.error_derive_forbidden_on_non_adt(&derives, &item); } let mut item = self.fully_configure(item); @@ -483,14 +484,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { for path in derives { let expn_id = ExpnId::fresh(None); derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id)); - invocations.push(Invocation { - kind: InvocationKind::Derive { path, item: item.clone() }, - fragment_kind: invoc.fragment_kind, - expansion_data: ExpansionData { - id: expn_id, - ..invoc.expansion_data.clone() + invocations.push(( + Invocation { + kind: InvocationKind::Derive { path, item: item.clone() }, + fragment_kind: invoc.fragment_kind, + expansion_data: ExpansionData { + id: expn_id, + ..invoc.expansion_data.clone() + }, }, - }); + None, + )); } let fragment = invoc.fragment_kind.expect_from_annotatables(::std::iter::once(item)); @@ -498,6 +502,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } }; + progress = true; if expanded_fragments.len() < depth { expanded_fragments.push(Vec::new()); } @@ -521,6 +526,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fragment_with_placeholders } + fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) { + let attr = attr::find_by_name(item.attrs(), sym::derive); + let span = attr.map_or(item.span(), |attr| attr.span); + let mut err = self + .cx + .struct_span_err(span, "`derive` may only be applied to structs, enums and unions"); + if let Some(ast::Attribute { style: ast::AttrStyle::Inner, .. }) = attr { + let trait_list = derives.iter().map(|t| pprust::path_to_string(t)).collect::>(); + let suggestion = format!("#[derive({})]", trait_list.join(", ")); + err.span_suggestion( + span, + "try an outer attribute", + suggestion, + // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT + Applicability::MaybeIncorrect, + ); + } + err.emit(); + } + fn resolve_imports(&mut self) { if self.monotonic { self.cx.resolver.resolve_imports(); @@ -535,7 +560,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { &mut self, mut fragment: AstFragment, extra_placeholders: &[NodeId], - ) -> (AstFragment, Vec) { + ) -> (AstFragment, Vec<(Invocation, Option)>) { // Resolve `$crate`s in the fragment for pretty-printing. self.cx.resolver.resolve_dollar_crates(); @@ -606,25 +631,46 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment { - if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { - let expn_data = self.cx.current_expansion.id.expn_data(); - let suggested_limit = self.cx.ecfg.recursion_limit * 2; - let mut err = self.cx.struct_span_err( + fn error_recursion_limit_reached(&mut self) { + let expn_data = self.cx.current_expansion.id.expn_data(); + let suggested_limit = self.cx.ecfg.recursion_limit * 2; + self.cx + .struct_span_err( expn_data.call_site, &format!("recursion limit reached while expanding `{}`", expn_data.kind.descr()), - ); - err.help(&format!( + ) + .help(&format!( "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", suggested_limit, self.cx.ecfg.crate_name, - )); - err.emit(); - self.cx.trace_macros_diag(); - FatalError.raise(); + )) + .emit(); + self.cx.trace_macros_diag(); + FatalError.raise(); + } + + /// A macro's expansion does not fit in this fragment kind. + /// For example, a non-type macro in a type position. + fn error_wrong_fragment_kind(&mut self, kind: AstFragmentKind, mac: &ast::MacCall, span: Span) { + let msg = format!( + "non-{kind} macro in {kind} position: {path}", + kind = kind.name(), + path = pprust::path_to_string(&mac.path), + ); + self.cx.span_err(span, &msg); + self.cx.trace_macros_diag(); + } + + fn expand_invoc( + &mut self, + invoc: Invocation, + ext: &SyntaxExtensionKind, + ) -> ExpandResult { + if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { + self.error_recursion_limit_reached(); } let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); - match invoc.kind { + ExpandResult::Ready(match invoc.kind { InvocationKind::Bang { mac, .. } => match ext { SyntaxExtensionKind::Bang(expander) => { self.gate_proc_macro_expansion_kind(span, fragment_kind); @@ -638,13 +684,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let result = if let Some(result) = fragment_kind.make_from(tok_result) { result } else { - let msg = format!( - "non-{kind} macro in {kind} position: {path}", - kind = fragment_kind.name(), - path = pprust::path_to_string(&mac.path), - ); - self.cx.span_err(span, &msg); - self.cx.trace_macros_diag(); + self.error_wrong_fragment_kind(fragment_kind, &mac, span); fragment_kind.dummy(span) }; self.cx.current_expansion.prior_type_ascription = prev; @@ -652,42 +692,41 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } _ => unreachable!(), }, - InvocationKind::Attr { attr, mut item, .. } => match ext { + InvocationKind::Attr { attr, mut item, derives, after_derive } => match ext { SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_input(&item); self.gate_proc_macro_attr_item(span, &item); - let item_tok = TokenTree::token( - token::Interpolated(Lrc::new(match item { - Annotatable::Item(item) => token::NtItem(item), - Annotatable::TraitItem(item) => token::NtTraitItem(item), - Annotatable::ImplItem(item) => token::NtImplItem(item), - Annotatable::ForeignItem(item) => token::NtForeignItem(item), - Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), - Annotatable::Expr(expr) => token::NtExpr(expr), - Annotatable::Arm(..) - | Annotatable::Field(..) - | Annotatable::FieldPat(..) - | Annotatable::GenericParam(..) - | Annotatable::Param(..) - | Annotatable::StructField(..) - | Annotatable::Variant(..) => panic!("unexpected annotatable"), - })), - DUMMY_SP, - ) - .into(); - let item = attr.unwrap_normal_item(); - if let MacArgs::Eq(..) = item.args { + let tokens = item.into_tokens(); + let attr_item = attr.unwrap_normal_item(); + if let MacArgs::Eq(..) = attr_item.args { self.cx.span_err(span, "key-value macro attributes are not supported"); } let tok_result = - expander.expand(self.cx, span, item.args.inner_tokens(), item_tok); - self.parse_ast_fragment(tok_result, fragment_kind, &item.path, span) + expander.expand(self.cx, span, attr_item.args.inner_tokens(), tokens); + self.parse_ast_fragment(tok_result, fragment_kind, &attr_item.path, span) } SyntaxExtensionKind::LegacyAttr(expander) => { match validate_attr::parse_meta(self.cx.parse_sess, &attr) { Ok(meta) => { - let item = expander.expand(self.cx, span, &meta, item); - fragment_kind.expect_from_annotatables(item) + let items = match expander.expand(self.cx, span, &meta, item) { + ExpandResult::Ready(items) => items, + ExpandResult::Retry(item, explanation) => { + // Reassemble the original invocation for retrying. + return ExpandResult::Retry( + Invocation { + kind: InvocationKind::Attr { + attr, + item, + derives, + after_derive, + }, + ..invoc + }, + explanation, + ); + } + }; + fragment_kind.expect_from_annotatables(items) } Err(mut err) => { err.emit(); @@ -709,19 +748,31 @@ impl<'a, 'b> MacroExpander<'a, 'b> { SyntaxExtensionKind::Derive(expander) | SyntaxExtensionKind::LegacyDerive(expander) => { if !item.derive_allowed() { - return fragment_kind.dummy(span); + return ExpandResult::Ready(fragment_kind.dummy(span)); } if let SyntaxExtensionKind::Derive(..) = ext { self.gate_proc_macro_input(&item); } let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path }; - let items = expander.expand(self.cx, span, &meta, item); + let items = match expander.expand(self.cx, span, &meta, item) { + ExpandResult::Ready(items) => items, + ExpandResult::Retry(item, explanation) => { + // Reassemble the original invocation for retrying. + return ExpandResult::Retry( + Invocation { + kind: InvocationKind::Derive { path: meta.path, item }, + ..invoc + }, + explanation, + ); + } + }; fragment_kind.expect_from_annotatables(items) } _ => unreachable!(), }, InvocationKind::DeriveContainer { .. } => unreachable!(), - } + }) } fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { @@ -775,7 +826,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { visit::walk_item(self, item); } - fn visit_mac(&mut self, _: &'ast ast::Mac) {} + fn visit_mac(&mut self, _: &'ast ast::MacCall) {} } if !self.cx.ecfg.proc_macro_hygiene() { @@ -821,7 +872,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { span: Span, ) -> AstFragment { let mut parser = self.cx.new_parser_from_tts(toks); - match parse_ast_fragment(&mut parser, kind, false) { + match parse_ast_fragment(&mut parser, kind) { Ok(fragment) => { ensure_complete_parse(&mut parser, path, kind.name(), span); fragment @@ -840,7 +891,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { pub fn parse_ast_fragment<'a>( this: &mut Parser<'a>, kind: AstFragmentKind, - macro_legacy_warnings: bool, ) -> PResult<'a, AstFragment> { Ok(match kind { AstFragmentKind::Items => { @@ -852,32 +902,30 @@ pub fn parse_ast_fragment<'a>( } AstFragmentKind::TraitItems => { let mut items = SmallVec::new(); - while this.token != token::Eof { - items.push(this.parse_trait_item(&mut false)?); + while let Some(item) = this.parse_trait_item()? { + items.extend(item); } AstFragment::TraitItems(items) } AstFragmentKind::ImplItems => { let mut items = SmallVec::new(); - while this.token != token::Eof { - items.push(this.parse_impl_item(&mut false)?); + while let Some(item) = this.parse_impl_item()? { + items.extend(item); } AstFragment::ImplItems(items) } AstFragmentKind::ForeignItems => { let mut items = SmallVec::new(); - while this.token != token::Eof { - items.push(this.parse_foreign_item()?); + while let Some(item) = this.parse_foreign_item()? { + items.extend(item); } AstFragment::ForeignItems(items) } AstFragmentKind::Stmts => { let mut stmts = SmallVec::new(); - while this.token != token::Eof && - // won't make progress on a `}` - this.token != token::CloseDelim(token::Brace) - { - if let Some(stmt) = this.parse_full_stmt(macro_legacy_warnings)? { + // Won't make progress on a `}`. + while this.token != token::Eof && this.token != token::CloseDelim(token::Brace) { + if let Some(stmt) = this.parse_full_stmt()? { stmts.push(stmt); } } @@ -943,7 +991,7 @@ pub fn ensure_complete_parse<'a>( struct InvocationCollector<'a, 'b> { cx: &'a mut ExtCtxt<'b>, cfg: StripUnconfigured<'a>, - invocations: Vec, + invocations: Vec<(Invocation, Option)>, monotonic: bool, } @@ -965,19 +1013,27 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { }; let expn_id = ExpnId::fresh(expn_data); let vis = kind.placeholder_visibility(); - self.invocations.push(Invocation { - kind, - fragment_kind, - expansion_data: ExpansionData { - id: expn_id, - depth: self.cx.current_expansion.depth + 1, - ..self.cx.current_expansion.clone() + self.invocations.push(( + Invocation { + kind, + fragment_kind, + expansion_data: ExpansionData { + id: expn_id, + depth: self.cx.current_expansion.depth + 1, + ..self.cx.current_expansion.clone() + }, }, - }); + None, + )); placeholder(fragment_kind, NodeId::placeholder_from_expn_id(expn_id), vis) } - fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment { + fn collect_bang( + &mut self, + mac: ast::MacCall, + span: Span, + kind: AstFragmentKind, + ) -> AstFragment { self.collect(kind, InvocationKind::Bang { mac, span }) } @@ -1030,13 +1086,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } /// If `item` is an attr invocation, remove and return the macro attribute and derive traits. - fn classify_item( + fn classify_item( &mut self, - item: &mut T, - ) -> (Option, Vec, /* after_derive */ bool) - where - T: HasAttrs, - { + item: &mut impl HasAttrs, + ) -> (Option, Vec, /* after_derive */ bool) { let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false); item.visit_attrs(|mut attrs| { @@ -1050,9 +1103,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { /// Alternative to `classify_item()` that ignores `#[derive]` so invocations fallthrough /// to the unused-attributes lint (making it an error on statements and expressions /// is a breaking change) - fn classify_nonitem( + fn classify_nonitem( &mut self, - nonitem: &mut T, + nonitem: &mut impl HasAttrs, ) -> (Option, /* after_derive */ bool) { let (mut attr, mut after_derive) = (None, false); @@ -1082,6 +1135,16 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { .note("this may become a hard error in a future release") .emit(); } + + if attr.doc_str().is_some() { + self.cx.parse_sess.buffer_lint_with_diagnostic( + &UNUSED_DOC_COMMENTS, + attr.span, + ast::CRATE_NODE_ID, + "unused doc comment", + BuiltinLintDiagnostics::UnusedDocComment(attr.span), + ); + } } } } @@ -1113,7 +1176,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .into_inner(); } - if let ast::ExprKind::Mac(mac) = expr.kind { + if let ast::ExprKind::MacCall(mac) = expr.kind { self.check_attributes(&expr.attrs); self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner() } else { @@ -1260,7 +1323,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .map(|expr| expr.into_inner()); } - if let ast::ExprKind::Mac(mac) = expr.kind { + if let ast::ExprKind::MacCall(mac) = expr.kind { self.check_attributes(&expr.attrs); self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr) .make_opt_expr() @@ -1277,12 +1340,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_pat(&mut self, pat: &mut P) { self.cfg.configure_pat(pat); match pat.kind { - PatKind::Mac(_) => {} + PatKind::MacCall(_) => {} _ => return noop_visit_pat(pat, self), } visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) { - PatKind::Mac(mac) => self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat(), + PatKind::MacCall(mac) => { + self.collect_bang(mac, pat.span, AstFragmentKind::Pat).make_pat() + } _ => unreachable!(), }); } @@ -1314,7 +1379,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } - if let StmtKind::Mac(mac) = stmt.kind { + if let StmtKind::MacCall(mac) = stmt.kind { let (mac, style, attrs) = mac.into_inner(); self.check_attributes(&attrs); let mut placeholder = @@ -1362,66 +1427,83 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_items(); } + let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck. + let ident = item.ident; + let span = item.span; + match item.kind { - ast::ItemKind::Mac(..) => { + ast::ItemKind::MacCall(..) => { + item.attrs = attrs; self.check_attributes(&item.attrs); item.and_then(|item| match item.kind { - ItemKind::Mac(mac) => self - .collect( - AstFragmentKind::Items, - InvocationKind::Bang { mac, span: item.span }, - ) + ItemKind::MacCall(mac) => self + .collect(AstFragmentKind::Items, InvocationKind::Bang { mac, span }) .make_items(), _ => unreachable!(), }) } - ast::ItemKind::Mod(ast::Mod { inner, .. }) => { - if item.ident == Ident::invalid() { - return noop_flat_map_item(item, self); - } - - let orig_directory_ownership = self.cx.current_expansion.directory_ownership; + ast::ItemKind::Mod(ref mut old_mod @ ast::Mod { .. }) if ident != Ident::invalid() => { + let sess = self.cx.parse_sess; + let orig_ownership = self.cx.current_expansion.directory_ownership; let mut module = (*self.cx.current_expansion.module).clone(); - module.mod_path.push(item.ident); - - // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`). - // In the non-inline case, `inner` is never the dummy span (cf. `parse_item_mod`). - // Thus, if `inner` is the dummy span, we know the module is inline. - let inline_module = item.span.contains(inner) || inner.is_dummy(); - - if inline_module { - if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, sym::path) { - self.cx.current_expansion.directory_ownership = - DirectoryOwnership::Owned { relative: None }; - module.directory.push(&*path.as_str()); - } else { - module.directory.push(&*item.ident.as_str()); - } + + let pushed = &mut false; // Record `parse_external_mod` pushing so we can pop. + let dir = Directory { ownership: orig_ownership, path: module.directory }; + let Directory { ownership, path } = if old_mod.inline { + // Inline `mod foo { ... }`, but we still need to push directories. + item.attrs = attrs; + push_directory(ident, &item.attrs, dir) } else { - let path = self.cx.parse_sess.source_map().span_to_unmapped_path(inner); - let mut path = match path { - FileName::Real(path) => path, - other => PathBuf::from(other.to_string()), + // We have an outline `mod foo;` so we need to parse the file. + let (new_mod, dir) = + parse_external_mod(sess, ident, span, dir, &mut attrs, pushed); + + let krate = ast::Crate { + span: new_mod.inner, + module: new_mod, + attrs, + proc_macros: vec![], }; - let directory_ownership = match path.file_name().unwrap().to_str() { - Some("mod.rs") => DirectoryOwnership::Owned { relative: None }, - Some(_) => DirectoryOwnership::Owned { relative: Some(item.ident) }, - None => DirectoryOwnership::UnownedViaMod, + if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded { + extern_mod_loaded(&krate); + } + + *old_mod = krate.module; + item.attrs = krate.attrs; + // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure. + item = match self.configure(item) { + Some(node) => node, + None => { + if *pushed { + sess.included_mod_stack.borrow_mut().pop(); + } + return Default::default(); + } }; - path.pop(); - module.directory = path; - self.cx.current_expansion.directory_ownership = directory_ownership; - } + dir + }; + // Set the module info before we flat map. + self.cx.current_expansion.directory_ownership = ownership; + module.directory = path; + module.mod_path.push(ident); let orig_module = mem::replace(&mut self.cx.current_expansion.module, Rc::new(module)); + let result = noop_flat_map_item(item, self); + + // Restore the module info. self.cx.current_expansion.module = orig_module; - self.cx.current_expansion.directory_ownership = orig_directory_ownership; + self.cx.current_expansion.directory_ownership = orig_ownership; + if *pushed { + sess.included_mod_stack.borrow_mut().pop(); + } result } - - _ => noop_flat_map_item(item, self), + _ => { + item.attrs = attrs; + noop_flat_map_item(item, self) + } } } @@ -1442,10 +1524,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } match item.kind { - ast::AssocItemKind::Macro(..) => { + ast::AssocItemKind::MacCall(..) => { self.check_attributes(&item.attrs); item.and_then(|item| match item.kind { - ast::AssocItemKind::Macro(mac) => self + ast::AssocItemKind::MacCall(mac) => self .collect_bang(mac, item.span, AstFragmentKind::TraitItems) .make_trait_items(), _ => unreachable!(), @@ -1472,10 +1554,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } match item.kind { - ast::AssocItemKind::Macro(..) => { + ast::AssocItemKind::MacCall(..) => { self.check_attributes(&item.attrs); item.and_then(|item| match item.kind { - ast::AssocItemKind::Macro(mac) => self + ast::AssocItemKind::MacCall(mac) => self .collect_bang(mac, item.span, AstFragmentKind::ImplItems) .make_impl_items(), _ => unreachable!(), @@ -1487,12 +1569,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_ty(&mut self, ty: &mut P) { match ty.kind { - ast::TyKind::Mac(_) => {} + ast::TyKind::MacCall(_) => {} _ => return noop_visit_ty(ty, self), }; visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) { - ast::TyKind::Mac(mac) => self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty(), + ast::TyKind::MacCall(mac) => { + self.collect_bang(mac, ty.span, AstFragmentKind::Ty).make_ty() + } _ => unreachable!(), }); } @@ -1521,10 +1605,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } match foreign_item.kind { - ast::ForeignItemKind::Macro(..) => { + ast::ForeignItemKind::MacCall(..) => { self.check_attributes(&foreign_item.attrs); foreign_item.and_then(|item| match item.kind { - ast::ForeignItemKind::Macro(mac) => self + ast::ForeignItemKind::MacCall(mac) => self .collect_bang(mac, item.span, AstFragmentKind::ForeignItems) .make_foreign_items(), _ => unreachable!(), @@ -1654,10 +1738,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } } else { - let mut err = self.cx.struct_span_err( - it.span(), - &format!("expected path to external documentation"), - ); + let mut err = self + .cx + .struct_span_err(it.span(), "expected path to external documentation"); // Check if the user erroneously used `doc(include(...))` syntax. let literal = it.meta_item_list().and_then(|list| { diff --git a/src/librustc_expand/lib.rs b/src/librustc_expand/lib.rs index f119c956ced..0320a275e5d 100644 --- a/src/librustc_expand/lib.rs +++ b/src/librustc_expand/lib.rs @@ -1,9 +1,11 @@ +#![feature(bool_to_option)] #![feature(cow_is_borrowed)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] #![feature(proc_macro_span)] +#![feature(try_blocks)] extern crate proc_macro as pm; @@ -33,8 +35,10 @@ pub use mbe::macro_rules::compile_declarative_macro; crate use rustc_span::hygiene; pub mod base; pub mod build; +#[macro_use] +pub mod config; pub mod expand; -pub use rustc_parse::config; +pub mod module; pub mod proc_macro; crate mod mbe; diff --git a/src/librustc_expand/mbe.rs b/src/librustc_expand/mbe.rs index fe207a4c876..57957a1fa8b 100644 --- a/src/librustc_expand/mbe.rs +++ b/src/librustc_expand/mbe.rs @@ -9,9 +9,9 @@ crate mod macro_rules; crate mod quoted; crate mod transcribe; -use syntax::ast; -use syntax::token::{self, Token, TokenKind}; -use syntax::tokenstream::DelimSpan; +use rustc_ast::ast; +use rustc_ast::token::{self, Token, TokenKind}; +use rustc_ast::tokenstream::DelimSpan; use rustc_span::Span; diff --git a/src/librustc_expand/mbe/macro_check.rs b/src/librustc_expand/mbe/macro_check.rs index 47865b2fb9f..582c26162ed 100644 --- a/src/librustc_expand/mbe/macro_check.rs +++ b/src/librustc_expand/mbe/macro_check.rs @@ -106,13 +106,13 @@ //! bound. use crate::mbe::{KleeneToken, TokenTree}; +use rustc_ast::ast::NodeId; +use rustc_ast::token::{DelimToken, Token, TokenKind}; use rustc_data_structures::fx::FxHashMap; use rustc_session::lint::builtin::META_VARIABLE_MISUSE; use rustc_session::parse::ParseSess; -use rustc_span::symbol::{kw, sym}; -use rustc_span::{symbol::Ident, MultiSpan, Span}; -use syntax::ast::NodeId; -use syntax::token::{DelimToken, Token, TokenKind}; +use rustc_span::symbol::kw; +use rustc_span::{symbol::MacroRulesNormalizedIdent, MultiSpan, Span}; use smallvec::SmallVec; @@ -179,7 +179,7 @@ struct BinderInfo { } /// An environment of meta-variables to their binder information. -type Binders = FxHashMap; +type Binders = FxHashMap; /// The state at which we entered a macro definition in the RHS of another macro definition. struct MacroState<'a> { @@ -245,6 +245,7 @@ fn check_binders( if macros.is_empty() { sess.span_diagnostic.span_bug(span, "unexpected MetaVar in lhs"); } + let name = MacroRulesNormalizedIdent::new(name); // There are 3 possibilities: if let Some(prev_info) = binders.get(&name) { // 1. The meta-variable is already bound in the current LHS: This is an error. @@ -264,6 +265,7 @@ fn check_binders( if !macros.is_empty() { sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in nested lhs"); } + let name = MacroRulesNormalizedIdent::new(name); if let Some(prev_info) = get_binder_info(macros, binders, name) { // Duplicate binders at the top-level macro definition are errors. The lint is only // for nested macro definitions. @@ -300,7 +302,7 @@ fn check_binders( fn get_binder_info<'a>( mut macros: &'a Stack<'a, MacroState<'a>>, binders: &'a Binders, - name: Ident, + name: MacroRulesNormalizedIdent, ) -> Option<&'a BinderInfo> { binders.get(&name).or_else(|| macros.find_map(|state| state.binders.get(&name))) } @@ -331,6 +333,7 @@ fn check_occurrences( sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in rhs") } TokenTree::MetaVar(span, name) => { + let name = MacroRulesNormalizedIdent::new(name); check_ops_is_prefix(sess, node_id, macros, binders, ops, span, name); } TokenTree::Delimited(_, ref del) => { @@ -392,7 +395,7 @@ fn check_nested_occurrences( NestedMacroState::Empty, &TokenTree::Token(Token { kind: TokenKind::Ident(name, false), .. }), ) => { - if name == sym::macro_rules { + if name == kw::MacroRules { state = NestedMacroState::MacroRules; } else if name == kw::Macro { state = NestedMacroState::Macro; @@ -419,10 +422,10 @@ fn check_nested_occurrences( | (NestedMacroState::MacroName, &TokenTree::Delimited(_, ref del)) if del.delim == DelimToken::Brace => { - let legacy = state == NestedMacroState::MacroRulesNotName; + let macro_rules = state == NestedMacroState::MacroRulesNotName; state = NestedMacroState::Empty; let rest = - check_nested_macro(sess, node_id, legacy, &del.tts, &nested_macros, valid); + check_nested_macro(sess, node_id, macro_rules, &del.tts, &nested_macros, valid); // If we did not check the whole macro definition, then check the rest as if outside // the macro definition. check_nested_occurrences( @@ -493,21 +496,21 @@ fn check_nested_occurrences( /// Arguments: /// - `sess` is used to emit diagnostics and lints /// - `node_id` is used to emit lints -/// - `legacy` specifies whether the macro is legacy +/// - `macro_rules` specifies whether the macro is `macro_rules` /// - `tts` is checked as a list of (LHS) => {RHS} /// - `macros` is the stack of outer macros /// - `valid` is set in case of errors fn check_nested_macro( sess: &ParseSess, node_id: NodeId, - legacy: bool, + macro_rules: bool, tts: &[TokenTree], macros: &Stack<'_, MacroState<'_>>, valid: &mut bool, ) -> usize { let n = tts.len(); let mut i = 0; - let separator = if legacy { TokenKind::Semi } else { TokenKind::Comma }; + let separator = if macro_rules { TokenKind::Semi } else { TokenKind::Comma }; loop { // We expect 3 token trees: `(LHS) => {RHS}`. The separator is checked after. if i + 2 >= n @@ -522,7 +525,7 @@ fn check_nested_macro( let mut binders = Binders::default(); check_binders(sess, node_id, lhs, macros, &mut binders, &Stack::Empty, valid); check_occurrences(sess, node_id, rhs, macros, &binders, &Stack::Empty, valid); - // Since the last semicolon is optional for legacy macros and decl_macro are not terminated, + // Since the last semicolon is optional for `macro_rules` macros and decl_macro are not terminated, // we increment our checked position by how many token trees we already checked (the 3 // above) before checking for the separator. i += 3; @@ -552,7 +555,7 @@ fn check_ops_is_prefix( binders: &Binders, ops: &Stack<'_, KleeneToken>, span: Span, - name: Ident, + name: MacroRulesNormalizedIdent, ) { let macros = macros.push(MacroState { binders, ops: ops.into() }); // Accumulates the stacks the operators of each state until (and including when) the @@ -598,7 +601,7 @@ fn ops_is_prefix( sess: &ParseSess, node_id: NodeId, span: Span, - name: Ident, + name: MacroRulesNormalizedIdent, binder_ops: &[KleeneToken], occurrence_ops: &[KleeneToken], ) { diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index 5bf7602ea6e..3b9158f4445 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -76,13 +76,13 @@ use TokenTreeOrTokenTreeSlice::*; use crate::mbe::{self, TokenTree}; +use rustc_ast::ast::Name; +use rustc_ast::ptr::P; +use rustc_ast::token::{self, DocComment, Nonterminal, Token}; use rustc_ast_pretty::pprust; use rustc_parse::parser::{FollowedByType, Parser, PathStyle}; use rustc_session::parse::ParseSess; -use rustc_span::symbol::{kw, sym, Symbol}; -use syntax::ast::{Ident, Name}; -use syntax::ptr::P; -use syntax::token::{self, DocComment, Nonterminal, Token}; +use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent, Symbol}; use rustc_errors::{FatalError, PResult}; use rustc_span::Span; @@ -273,9 +273,10 @@ crate enum ParseResult { Error(rustc_span::Span, String), } -/// A `ParseResult` where the `Success` variant contains a mapping of `Ident`s to `NamedMatch`es. -/// This represents the mapping of metavars to the token trees they bind to. -crate type NamedParseResult = ParseResult>; +/// A `ParseResult` where the `Success` variant contains a mapping of +/// `MacroRulesNormalizedIdent`s to `NamedMatch`es. This represents the mapping +/// of metavars to the token trees they bind to. +crate type NamedParseResult = ParseResult>; /// Count how many metavars are named in the given matcher `ms`. pub(super) fn count_names(ms: &[TokenTree]) -> usize { @@ -368,7 +369,7 @@ fn nameize>( sess: &ParseSess, m: &TokenTree, res: &mut I, - ret_val: &mut FxHashMap, + ret_val: &mut FxHashMap, ) -> Result<(), (rustc_span::Span, String)> { match *m { TokenTree::Sequence(_, ref seq) => { @@ -386,7 +387,9 @@ fn nameize>( return Err((span, "missing fragment specifier".to_string())); } } - TokenTree::MetaVarDecl(sp, bind_name, _) => match ret_val.entry(bind_name) { + TokenTree::MetaVarDecl(sp, bind_name, _) => match ret_val + .entry(MacroRulesNormalizedIdent::new(bind_name)) + { Vacant(spot) => { spot.insert(res.next().unwrap()); } @@ -750,11 +753,8 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na /// The token is an identifier, but not `_`. /// We prohibit passing `_` to macros expecting `ident` for now. -fn get_macro_name(token: &Token) -> Option<(Name, bool)> { - match token.kind { - token::Ident(name, is_raw) if name != kw::Underscore => Some((name, is_raw)), - _ => None, - } +fn get_macro_ident(token: &Token) -> Option<(Ident, bool)> { + token.ident().filter(|(ident, _)| ident.name != kw::Underscore) } /// Checks whether a non-terminal may begin with a particular token. @@ -777,7 +777,7 @@ fn may_begin_with(token: &Token, name: Name) -> bool { && !token.is_keyword(kw::Let) } sym::ty => token.can_begin_type(), - sym::ident => get_macro_name(token).is_some(), + sym::ident => get_macro_ident(token).is_some(), sym::literal => token.can_begin_literal_or_bool(), sym::vis => match token.kind { // The follow-set of :vis + "priv" keyword + interpolated @@ -856,8 +856,6 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal { if name == sym::tt { return token::NtTT(p.parse_token_tree()); } - // check at the beginning and the parser checks after each bump - p.process_potential_macro_variable(); match parse_nt_inner(p, sp, name) { Ok(nt) => nt, Err(mut err) => { @@ -884,10 +882,9 @@ fn parse_nt_inner<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> PResult<'a, sym::ty => token::NtTy(p.parse_ty()?), // this could be handled like a token, since it is one sym::ident => { - if let Some((name, is_raw)) = get_macro_name(&p.token) { - let span = p.token.span; + if let Some((ident, is_raw)) = get_macro_ident(&p.token) { p.bump(); - token::NtIdent(Ident::new(name, span), is_raw) + token::NtIdent(ident, is_raw) } else { let token_str = pprust::token_to_string(&p.token); let msg = &format!("expected ident, found {}", &token_str); diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 9e6edee265c..3de2169f114 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -1,4 +1,4 @@ -use crate::base::{DummyResult, ExpansionData, ExtCtxt, MacResult, TTMacroExpander}; +use crate::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; use crate::base::{SyntaxExtension, SyntaxExtensionKind}; use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind}; use crate::mbe; @@ -8,6 +8,9 @@ use crate::mbe::macro_parser::{Error, Failure, Success}; use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq}; use crate::mbe::transcribe::transcribe; +use rustc_ast::ast; +use rustc_ast::token::{self, NtTT, Token, TokenKind::*}; +use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; use rustc_data_structures::fx::FxHashMap; @@ -15,15 +18,11 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder, FatalError}; use rustc_feature::Features; use rustc_parse::parser::Parser; -use rustc_parse::Directory; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{kw, sym, MacroRulesNormalizedIdent, Symbol}; use rustc_span::Span; -use syntax::ast; -use syntax::token::{self, NtTT, Token, TokenKind::*}; -use syntax::tokenstream::{DelimSpan, TokenStream}; use log::debug; use std::borrow::Cow; @@ -87,7 +86,7 @@ fn suggest_slice_pat(e: &mut DiagnosticBuilder<'_>, site_span: Span, parser: &Pa impl<'a> ParserAnyMacro<'a> { crate fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self; - let fragment = panictry!(parse_ast_fragment(parser, kind, true).map_err(|mut e| { + let fragment = panictry!(parse_ast_fragment(parser, kind).map_err(|mut e| { if parser.token == token::Eof && e.message().ends_with(", found ``") { if !e.span.is_dummy() { // early end of macro arm (#52866) @@ -105,10 +104,10 @@ impl<'a> ParserAnyMacro<'a> { if e.span.is_dummy() { // Get around lack of span in error (#30128) e.replace_span_with(site_span); - if parser.sess.source_map().span_to_filename(arm_span).is_real() { + if !parser.sess.source_map().is_imported(arm_span) { e.span_label(arm_span, "in this macro arm"); } - } else if !parser.sess.source_map().span_to_filename(parser.token.span).is_real() { + } else if parser.sess.source_map().is_imported(parser.token.span) { e.span_label(site_span, "in this macro invocation"); } match kind { @@ -182,6 +181,8 @@ fn generic_extension<'cx>( lhses: &[mbe::TokenTree], rhses: &[mbe::TokenTree], ) -> Box { + let sess = cx.parse_sess; + if cx.trace_macros() { let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(arg.clone())); trace_macros_note(&mut cx.expansions, sp, msg); @@ -191,9 +192,9 @@ fn generic_extension<'cx>( let mut best_failure: Option<(Token, &str)> = None; // We create a base parser that can be used for the "black box" parts. - // Every iteration needs a fresh copy of that base parser. However, the - // parser is not mutated on many of the iterations, particularly when - // dealing with macros like this: + // Every iteration needs a fresh copy of that parser. However, the parser + // is not mutated on many of the iterations, particularly when dealing with + // macros like this: // // macro_rules! foo { // ("a") => (A); @@ -209,11 +210,9 @@ fn generic_extension<'cx>( // hacky, but speeds up the `html5ever` benchmark significantly. (Issue // 68836 suggests a more comprehensive but more complex change to deal with // this situation.) - let base_parser = base_parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone()); + let parser = parser_from_cx(sess, arg.clone()); for (i, lhs) in lhses.iter().enumerate() { - let mut parser = Cow::Borrowed(&base_parser); - // try each arm's matchers let lhs_tt = match *lhs { mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], @@ -224,13 +223,13 @@ fn generic_extension<'cx>( // This is used so that if a matcher is not `Success(..)`ful, // then the spans which became gated when parsing the unsuccessful matcher // are not recorded. On the first `Success(..)`ful matcher, the spans are merged. - let mut gated_spans_snaphot = mem::take(&mut *cx.parse_sess.gated_spans.spans.borrow_mut()); + let mut gated_spans_snapshot = mem::take(&mut *sess.gated_spans.spans.borrow_mut()); - match parse_tt(&mut parser, lhs_tt) { + match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) { Success(named_matches) => { // The matcher was `Success(..)`ful. // Merge the gated spans from parsing the matcher with the pre-existing ones. - cx.parse_sess.gated_spans.merge(gated_spans_snaphot); + sess.gated_spans.merge(gated_spans_snapshot); let rhs = match rhses[i] { // ignore delimiters @@ -259,16 +258,11 @@ fn generic_extension<'cx>( trace_macros_note(&mut cx.expansions, sp, msg); } - let directory = Directory { - path: cx.current_expansion.module.directory.clone(), - ownership: cx.current_expansion.directory_ownership, - }; - let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false, None); + let mut p = Parser::new(sess, tts, false, None); p.root_module_name = cx.current_expansion.module.mod_path.last().map(|id| id.to_string()); p.last_type_ascription = cx.current_expansion.prior_type_ascription; - p.process_potential_macro_variable(); // Let the context choose how to interpret the result. // Weird, but useful for X-macros. return Box::new(ParserAnyMacro { @@ -291,15 +285,15 @@ fn generic_extension<'cx>( // The matcher was not `Success(..)`ful. // Restore to the state before snapshotting and maybe try again. - mem::swap(&mut gated_spans_snaphot, &mut cx.parse_sess.gated_spans.spans.borrow_mut()); + mem::swap(&mut gated_spans_snapshot, &mut sess.gated_spans.spans.borrow_mut()); } - drop(base_parser); + drop(parser); let (token, label) = best_failure.expect("ran no matchers"); let span = token.span.substitute_dummy(sp); let mut err = cx.struct_span_err(span, &parse_failure_msg(&token)); err.span_label(span, label); - if !def_span.is_dummy() && cx.source_map().span_to_filename(def_span).is_real() { + if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) { err.span_label(cx.source_map().def_span(def_span), "when calling this macro"); } @@ -311,9 +305,7 @@ fn generic_extension<'cx>( mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..], _ => continue, }; - let base_parser = - base_parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone()); - match parse_tt(&mut Cow::Borrowed(&base_parser), lhs_tt) { + match parse_tt(&mut Cow::Borrowed(&parser_from_cx(sess, arg.clone())), lhs_tt) { Success(_) => { if comma_span.is_dummy() { err.note("you might be missing a comma"); @@ -353,8 +345,8 @@ pub fn compile_declarative_macro( let tt_spec = ast::Ident::new(sym::tt, def.span); // Parse the macro_rules! invocation - let (is_legacy, body) = match &def.kind { - ast::ItemKind::MacroDef(macro_def) => (macro_def.legacy, macro_def.body.inner_tokens()), + let (macro_rules, body) = match &def.kind { + ast::ItemKind::MacroDef(def) => (def.macro_rules, def.body.inner_tokens()), _ => unreachable!(), }; @@ -373,7 +365,7 @@ pub fn compile_declarative_macro( mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec), ], separator: Some(Token::new( - if is_legacy { token::Semi } else { token::Comma }, + if macro_rules { token::Semi } else { token::Comma }, def.span, )), kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span), @@ -385,7 +377,7 @@ pub fn compile_declarative_macro( DelimSpan::dummy(), Lrc::new(mbe::SequenceRepetition { tts: vec![mbe::TokenTree::token( - if is_legacy { token::Semi } else { token::Comma }, + if macro_rules { token::Semi } else { token::Comma }, def.span, )], separator: None, @@ -395,8 +387,8 @@ pub fn compile_declarative_macro( ), ]; - let base_parser = Parser::new(sess, body, None, true, true, rustc_parse::MACRO_ARGUMENTS); - let argument_map = match parse_tt(&mut Cow::Borrowed(&base_parser), &argument_gram) { + let parser = Parser::new(sess, body, true, rustc_parse::MACRO_ARGUMENTS); + let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) { Success(m) => m, Failure(token, msg) => { let s = parse_failure_msg(&token); @@ -414,7 +406,7 @@ pub fn compile_declarative_macro( let mut valid = true; // Extract the arguments: - let lhses = match argument_map[&lhs_nm] { + let lhses = match argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] { MatchedSeq(ref s) => s .iter() .map(|m| { @@ -431,7 +423,7 @@ pub fn compile_declarative_macro( _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"), }; - let rhses = match argument_map[&rhs_nm] { + let rhses = match argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] { MatchedSeq(ref s) => s .iter() .map(|m| { @@ -459,7 +451,7 @@ pub fn compile_declarative_macro( // that is not lint-checked and trigger the "failed to process buffered lint here" bug. valid &= macro_check::check_meta_variables(sess, ast::CRATE_NODE_ID, def.span, &lhses, &rhses); - let (transparency, transparency_error) = attr::find_transparency(&def.attrs, is_legacy); + let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules); match transparency_error { Some(TransparencyError::UnknownTransparency(value, span)) => { diag.span_err(span, &format!("unknown macro transparency: `{}`", value)) @@ -973,7 +965,7 @@ fn check_matcher_core( msg, ts[..ts.len() - 1] .iter() - .map(|s| *s) + .copied() .collect::>() .join(", "), ts[ts.len() - 1], @@ -994,7 +986,7 @@ fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool { if let mbe::TokenTree::MetaVarDecl(_, _, frag_spec) = *tok { frag_can_be_followed_by_any(frag_spec.name) } else { - // (Non NT's can always be followed by anthing in matchers.) + // (Non NT's can always be followed by anything in matchers.) true } } @@ -1212,16 +1204,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { } } -fn base_parser_from_cx<'cx>( - current_expansion: &'cx ExpansionData, - sess: &'cx ParseSess, - tts: TokenStream, -) -> Parser<'cx> { - let directory = Directory { - path: current_expansion.module.directory.clone(), - ownership: current_expansion.directory_ownership, - }; - Parser::new(sess, tts, Some(directory), true, true, rustc_parse::MACRO_ARGUMENTS) +fn parser_from_cx(sess: &ParseSess, tts: TokenStream) -> Parser<'_> { + Parser::new(sess, tts, true, rustc_parse::MACRO_ARGUMENTS) } /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For diff --git a/src/librustc_expand/mbe/quoted.rs b/src/librustc_expand/mbe/quoted.rs index 9ae8ead1a72..b19fae65597 100644 --- a/src/librustc_expand/mbe/quoted.rs +++ b/src/librustc_expand/mbe/quoted.rs @@ -1,12 +1,12 @@ use crate::mbe::macro_parser; use crate::mbe::{Delimited, KleeneOp, KleeneToken, SequenceRepetition, TokenTree}; +use rustc_ast::ast; +use rustc_ast::token::{self, Token}; +use rustc_ast::tokenstream; use rustc_ast_pretty::pprust; use rustc_session::parse::ParseSess; use rustc_span::symbol::kw; -use syntax::ast; -use syntax::token::{self, Token}; -use syntax::tokenstream; use rustc_span::Span; @@ -112,7 +112,7 @@ fn parse_tree( sess.span_diagnostic.span_err(span.entire(), &msg); } // Parse the contents of the sequence itself - let sequence = parse(tts.into(), expect_matchers, sess); + let sequence = parse(tts, expect_matchers, sess); // Get the Kleene operator and optional separator let (separator, kleene) = parse_sep_and_kleene_op(trees, span.entire(), sess); // Count the number of captured "names" (i.e., named metavars) @@ -159,7 +159,7 @@ fn parse_tree( // descend into the delimited set and further parse it. tokenstream::TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited( span, - Lrc::new(Delimited { delim, tts: parse(tts.into(), expect_matchers, sess) }), + Lrc::new(Delimited { delim, tts: parse(tts, expect_matchers, sess) }), ), } } diff --git a/src/librustc_expand/mbe/transcribe.rs b/src/librustc_expand/mbe/transcribe.rs index 104a5233c9d..1b1093c9529 100644 --- a/src/librustc_expand/mbe/transcribe.rs +++ b/src/librustc_expand/mbe/transcribe.rs @@ -2,15 +2,16 @@ use crate::base::ExtCtxt; use crate::mbe; use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; +use rustc_ast::ast::MacCall; +use rustc_ast::mut_visit::{self, MutVisitor}; +use rustc_ast::token::{self, NtTT, Token}; +use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::pluralize; use rustc_span::hygiene::{ExpnId, Transparency}; +use rustc_span::symbol::MacroRulesNormalizedIdent; use rustc_span::Span; -use syntax::ast::{Ident, Mac}; -use syntax::mut_visit::{self, MutVisitor}; -use syntax::token::{self, NtTT, Token}; -use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use smallvec::{smallvec, SmallVec}; use std::mem; @@ -23,7 +24,7 @@ impl MutVisitor for Marker { *span = span.apply_mark(self.0, self.1) } - fn visit_mac(&mut self, mac: &mut Mac) { + fn visit_mac(&mut self, mac: &mut MacCall) { mut_visit::noop_visit_mac(mac, self) } } @@ -81,7 +82,7 @@ impl Iterator for Frame { /// Along the way, we do some additional error checking. pub(super) fn transcribe( cx: &ExtCtxt<'_>, - interp: &FxHashMap, + interp: &FxHashMap, src: Vec, transparency: Transparency, ) -> TokenStream { @@ -119,9 +120,9 @@ pub(super) fn transcribe( let tree = if let Some(tree) = stack.last_mut().unwrap().next() { // If it still has a TokenTree we have not looked at yet, use that tree. tree - } - // The else-case never produces a value for `tree` (it `continue`s or `return`s). - else { + } else { + // This else-case never produces a value for `tree` (it `continue`s or `return`s). + // Otherwise, if we have just reached the end of a sequence and we can keep repeating, // go back to the beginning of the sequence. if let Frame::Sequence { idx, sep, .. } = stack.last_mut().unwrap() { @@ -155,8 +156,7 @@ pub(super) fn transcribe( } // Step back into the parent Delimited. - let tree = - TokenTree::Delimited(span, forest.delim, TokenStream::new(result).into()); + let tree = TokenTree::Delimited(span, forest.delim, TokenStream::new(result)); result = result_stack.pop().unwrap(); result.push(tree.into()); } @@ -224,9 +224,10 @@ pub(super) fn transcribe( } // Replace the meta-var with the matched token tree from the invocation. - mbe::TokenTree::MetaVar(mut sp, mut ident) => { + mbe::TokenTree::MetaVar(mut sp, mut orignal_ident) => { // Find the matched nonterminal from the macro invocation, and use it to replace // the meta-var. + let ident = MacroRulesNormalizedIdent::new(orignal_ident); if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { if let MatchedNonterminal(ref nt) = cur_matched { // FIXME #2887: why do we apply a mark when matching a token tree meta-var @@ -250,9 +251,9 @@ pub(super) fn transcribe( // If we aren't able to match the meta-var, we push it back into the result but // with modified syntax context. (I believe this supports nested macros). marker.visit_span(&mut sp); - marker.visit_ident(&mut ident); + marker.visit_ident(&mut orignal_ident); result.push(TokenTree::token(token::Dollar, sp).into()); - result.push(TokenTree::Token(Token::from_ast_ident(ident)).into()); + result.push(TokenTree::Token(Token::from_ast_ident(orignal_ident)).into()); } } @@ -288,8 +289,8 @@ pub(super) fn transcribe( /// into the right place in nested matchers. If we attempt to descend too far, the macro writer has /// made a mistake, and we return `None`. fn lookup_cur_matched<'a>( - ident: Ident, - interpolations: &'a FxHashMap, + ident: MacroRulesNormalizedIdent, + interpolations: &'a FxHashMap, repeats: &[(usize, usize)], ) -> Option<&'a NamedMatch> { interpolations.get(&ident).map(|matched| { @@ -317,7 +318,7 @@ enum LockstepIterSize { /// A `MetaVar` with an actual `MatchedSeq`. The length of the match and the name of the /// meta-var are returned. - Constraint(usize, Ident), + Constraint(usize, MacroRulesNormalizedIdent), /// Two `Constraint`s on the same sequence had different lengths. This is an error. Contradiction(String), @@ -361,7 +362,7 @@ impl LockstepIterSize { /// multiple nested matcher sequences. fn lockstep_iter_size( tree: &mbe::TokenTree, - interpolations: &FxHashMap, + interpolations: &FxHashMap, repeats: &[(usize, usize)], ) -> LockstepIterSize { use mbe::TokenTree; @@ -377,6 +378,7 @@ fn lockstep_iter_size( }) } TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => { + let name = MacroRulesNormalizedIdent::new(name); match lookup_cur_matched(name, interpolations, repeats) { Some(matched) => match matched { MatchedNonterminal(_) => LockstepIterSize::Unconstrained, diff --git a/src/librustc_expand/module.rs b/src/librustc_expand/module.rs new file mode 100644 index 00000000000..2d5e4d4e889 --- /dev/null +++ b/src/librustc_expand/module.rs @@ -0,0 +1,306 @@ +use rustc_ast::ast::{self, Attribute, Ident, Mod}; +use rustc_ast::{attr, token}; +use rustc_errors::{struct_span_err, PResult}; +use rustc_parse::new_sub_parser_from_file; +use rustc_session::parse::ParseSess; +use rustc_span::source_map::{FileName, Span}; +use rustc_span::symbol::sym; + +use std::path::{self, Path, PathBuf}; + +#[derive(Clone)] +pub struct Directory { + pub path: PathBuf, + pub ownership: DirectoryOwnership, +} + +#[derive(Copy, Clone)] +pub enum DirectoryOwnership { + Owned { + // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`. + relative: Option, + }, + UnownedViaBlock, + UnownedViaMod, +} + +/// Information about the path to a module. +// Public for rustfmt usage. +pub struct ModulePath<'a> { + name: String, + path_exists: bool, + pub result: PResult<'a, ModulePathSuccess>, +} + +// Public for rustfmt usage. +pub struct ModulePathSuccess { + pub path: PathBuf, + pub ownership: DirectoryOwnership, +} + +crate fn parse_external_mod( + sess: &ParseSess, + id: ast::Ident, + span: Span, // The span to blame on errors. + Directory { mut ownership, path }: Directory, + attrs: &mut Vec, + pop_mod_stack: &mut bool, +) -> (Mod, Directory) { + // We bail on the first error, but that error does not cause a fatal error... (1) + let result: PResult<'_, _> = try { + // Extract the file path and the new ownership. + let mp = submod_path(sess, id, span, &attrs, ownership, &path)?; + ownership = mp.ownership; + + // Ensure file paths are acyclic. + let mut included_mod_stack = sess.included_mod_stack.borrow_mut(); + error_on_circular_module(sess, span, &mp.path, &included_mod_stack)?; + included_mod_stack.push(mp.path.clone()); + *pop_mod_stack = true; // We have pushed, so notify caller. + drop(included_mod_stack); + + // Actually parse the external file as amodule. + let mut p0 = new_sub_parser_from_file(sess, &mp.path, Some(id.to_string()), span); + let mut module = p0.parse_mod(&token::Eof)?; + module.0.inline = false; + module + }; + // (1) ...instead, we return a dummy module. + let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default(); + attrs.append(&mut new_attrs); + + // Extract the directory path for submodules of `module`. + let path = sess.source_map().span_to_unmapped_path(module.inner); + let mut path = match path { + FileName::Real(path) => path, + other => PathBuf::from(other.to_string()), + }; + path.pop(); + + (module, Directory { ownership, path }) +} + +fn error_on_circular_module<'a>( + sess: &'a ParseSess, + span: Span, + path: &Path, + included_mod_stack: &[PathBuf], +) -> PResult<'a, ()> { + if let Some(i) = included_mod_stack.iter().position(|p| *p == path) { + let mut err = String::from("circular modules: "); + for p in &included_mod_stack[i..] { + err.push_str(&p.to_string_lossy()); + err.push_str(" -> "); + } + err.push_str(&path.to_string_lossy()); + return Err(sess.span_diagnostic.struct_span_err(span, &err[..])); + } + Ok(()) +} + +crate fn push_directory( + id: Ident, + attrs: &[Attribute], + Directory { mut ownership, mut path }: Directory, +) -> Directory { + if let Some(filename) = attr::first_attr_value_str_by_name(attrs, sym::path) { + path.push(&*filename.as_str()); + ownership = DirectoryOwnership::Owned { relative: None }; + } else { + // We have to push on the current module name in the case of relative + // paths in order to ensure that any additional module paths from inline + // `mod x { ... }` come after the relative extension. + // + // For example, a `mod z { ... }` inside `x/y.rs` should set the current + // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`. + if let DirectoryOwnership::Owned { relative } = &mut ownership { + if let Some(ident) = relative.take() { + // Remove the relative offset. + path.push(&*ident.as_str()); + } + } + path.push(&*id.as_str()); + } + Directory { ownership, path } +} + +fn submod_path<'a>( + sess: &'a ParseSess, + id: ast::Ident, + span: Span, + attrs: &[Attribute], + ownership: DirectoryOwnership, + dir_path: &Path, +) -> PResult<'a, ModulePathSuccess> { + if let Some(path) = submod_path_from_attr(attrs, dir_path) { + let ownership = match path.file_name().and_then(|s| s.to_str()) { + // All `#[path]` files are treated as though they are a `mod.rs` file. + // This means that `mod foo;` declarations inside `#[path]`-included + // files are siblings, + // + // Note that this will produce weirdness when a file named `foo.rs` is + // `#[path]` included and contains a `mod foo;` declaration. + // If you encounter this, it's your own darn fault :P + Some(_) => DirectoryOwnership::Owned { relative: None }, + _ => DirectoryOwnership::UnownedViaMod, + }; + return Ok(ModulePathSuccess { ownership, path }); + } + + let relative = match ownership { + DirectoryOwnership::Owned { relative } => relative, + DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None, + }; + let ModulePath { path_exists, name, result } = + default_submod_path(sess, id, span, relative, dir_path); + match ownership { + DirectoryOwnership::Owned { .. } => Ok(result?), + DirectoryOwnership::UnownedViaBlock => { + let _ = result.map_err(|mut err| err.cancel()); + error_decl_mod_in_block(sess, span, path_exists, &name) + } + DirectoryOwnership::UnownedViaMod => { + let _ = result.map_err(|mut err| err.cancel()); + error_cannot_declare_mod_here(sess, span, path_exists, &name) + } + } +} + +fn error_decl_mod_in_block<'a, T>( + sess: &'a ParseSess, + span: Span, + path_exists: bool, + name: &str, +) -> PResult<'a, T> { + let msg = "Cannot declare a non-inline module inside a block unless it has a path attribute"; + let mut err = sess.span_diagnostic.struct_span_err(span, msg); + if path_exists { + let msg = format!("Maybe `use` the module `{}` instead of redeclaring it", name); + err.span_note(span, &msg); + } + Err(err) +} + +fn error_cannot_declare_mod_here<'a, T>( + sess: &'a ParseSess, + span: Span, + path_exists: bool, + name: &str, +) -> PResult<'a, T> { + let mut err = + sess.span_diagnostic.struct_span_err(span, "cannot declare a new module at this location"); + if !span.is_dummy() { + if let FileName::Real(src_path) = sess.source_map().span_to_filename(span) { + if let Some(stem) = src_path.file_stem() { + let mut dest_path = src_path.clone(); + dest_path.set_file_name(stem); + dest_path.push("mod.rs"); + err.span_note( + span, + &format!( + "maybe move this module `{}` to its own directory via `{}`", + src_path.display(), + dest_path.display() + ), + ); + } + } + } + if path_exists { + err.span_note( + span, + &format!("... or maybe `use` the module `{}` instead of possibly redeclaring it", name), + ); + } + Err(err) +} + +/// Derive a submodule path from the first found `#[path = "path_string"]`. +/// The provided `dir_path` is joined with the `path_string`. +// Public for rustfmt usage. +pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option { + // Extract path string from first `#[path = "path_string"]` attribute. + let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?; + let path_string = path_string.as_str(); + + // On windows, the base path might have the form + // `\\?\foo\bar` in which case it does not tolerate + // mixed `/` and `\` separators, so canonicalize + // `/` to `\`. + #[cfg(windows)] + let path_string = path_string.replace("/", "\\"); + + Some(dir_path.join(&*path_string)) +} + +/// Returns a path to a module. +// Public for rustfmt usage. +pub fn default_submod_path<'a>( + sess: &'a ParseSess, + id: ast::Ident, + span: Span, + relative: Option, + dir_path: &Path, +) -> ModulePath<'a> { + // If we're in a foo.rs file instead of a mod.rs file, + // we need to look for submodules in + // `./foo/.rs` and `./foo//mod.rs` rather than + // `./.rs` and `.//mod.rs`. + let relative_prefix_string; + let relative_prefix = if let Some(ident) = relative { + relative_prefix_string = format!("{}{}", ident.name, path::MAIN_SEPARATOR); + &relative_prefix_string + } else { + "" + }; + + let mod_name = id.name.to_string(); + let default_path_str = format!("{}{}.rs", relative_prefix, mod_name); + let secondary_path_str = + format!("{}{}{}mod.rs", relative_prefix, mod_name, path::MAIN_SEPARATOR); + let default_path = dir_path.join(&default_path_str); + let secondary_path = dir_path.join(&secondary_path_str); + let default_exists = sess.source_map().file_exists(&default_path); + let secondary_exists = sess.source_map().file_exists(&secondary_path); + + let result = match (default_exists, secondary_exists) { + (true, false) => Ok(ModulePathSuccess { + path: default_path, + ownership: DirectoryOwnership::Owned { relative: Some(id) }, + }), + (false, true) => Ok(ModulePathSuccess { + path: secondary_path, + ownership: DirectoryOwnership::Owned { relative: None }, + }), + (false, false) => { + let mut err = struct_span_err!( + sess.span_diagnostic, + span, + E0583, + "file not found for module `{}`", + mod_name, + ); + err.help(&format!( + "to create the module `{}`, create file \"{}\"", + mod_name, + default_path.display(), + )); + Err(err) + } + (true, true) => { + let mut err = struct_span_err!( + sess.span_diagnostic, + span, + E0584, + "file for module `{}` found at both {} and {}", + mod_name, + default_path_str, + secondary_path_str, + ); + err.help("delete or rename one of them to remove the ambiguity"); + Err(err) + } + }; + + ModulePath { name: mod_name, path_exists: default_exists || secondary_exists, result } +} diff --git a/src/librustc_expand/mut_visit/tests.rs b/src/librustc_expand/mut_visit/tests.rs index 49b9a1b1025..70fb8975d4d 100644 --- a/src/librustc_expand/mut_visit/tests.rs +++ b/src/librustc_expand/mut_visit/tests.rs @@ -1,9 +1,9 @@ use crate::tests::{matches_codepattern, string_to_crate}; +use rustc_ast::ast::{self, Ident}; +use rustc_ast::mut_visit::{self, MutVisitor}; +use rustc_ast::with_default_globals; use rustc_ast_pretty::pprust; -use syntax::ast::{self, Ident}; -use syntax::mut_visit::{self, MutVisitor}; -use syntax::with_default_globals; // This version doesn't care about getting comments or doc-strings in. fn fake_print_crate(s: &mut pprust::State<'_>, krate: &ast::Crate) { @@ -17,7 +17,7 @@ impl MutVisitor for ToZzIdentMutVisitor { fn visit_ident(&mut self, ident: &mut ast::Ident) { *ident = Ident::from_str("zz"); } - fn visit_mac(&mut self, mac: &mut ast::Mac) { + fn visit_mac(&mut self, mac: &mut ast::MacCall) { mut_visit::noop_visit_mac(mac, self) } } diff --git a/src/librustc_expand/parse/lexer/tests.rs b/src/librustc_expand/parse/lexer/tests.rs index c486839dad5..2cb6267e0f6 100644 --- a/src/librustc_expand/parse/lexer/tests.rs +++ b/src/librustc_expand/parse/lexer/tests.rs @@ -1,3 +1,6 @@ +use rustc_ast::token::{self, Token, TokenKind}; +use rustc_ast::util::comments::is_doc_comment; +use rustc_ast::with_default_globals; use rustc_data_structures::sync::Lrc; use rustc_errors::{emitter::EmitterWriter, Handler}; use rustc_parse::lexer::StringReader; @@ -5,9 +8,6 @@ use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Span}; -use syntax::token::{self, Token, TokenKind}; -use syntax::util::comments::is_doc_comment; -use syntax::with_default_globals; use std::io; use std::path::PathBuf; diff --git a/src/librustc_expand/parse/tests.rs b/src/librustc_expand/parse/tests.rs index 3641f03cb30..4add896258f 100644 --- a/src/librustc_expand/parse/tests.rs +++ b/src/librustc_expand/parse/tests.rs @@ -1,5 +1,11 @@ use crate::tests::{matches_codepattern, string_to_stream, with_error_checking_parse}; +use rustc_ast::ast::{self, Name, PatKind}; +use rustc_ast::ptr::P; +use rustc_ast::token::{self, Token}; +use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; +use rustc_ast::visit; +use rustc_ast::with_default_globals; use rustc_ast_pretty::pprust::item_to_string; use rustc_errors::PResult; use rustc_parse::new_parser_from_source_str; @@ -7,12 +13,6 @@ use rustc_session::parse::ParseSess; use rustc_span::source_map::FilePathMapping; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{BytePos, FileName, Pos, Span}; -use syntax::ast::{self, Name, PatKind}; -use syntax::ptr::P; -use syntax::token::{self, Token}; -use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree}; -use syntax::visit; -use syntax::with_default_globals; use std::path::PathBuf; @@ -65,7 +65,7 @@ fn string_to_tts_macro() { match tts { [TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }), TokenTree::Token(Token { kind: token::Not, .. }), TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), TokenTree::Delimited(_, macro_delim, macro_tts)] - if name_macro_rules == &sym::macro_rules && name_zip.as_str() == "zip" => + if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" => { let tts = ¯o_tts.trees().collect::>(); match &tts[..] { @@ -281,7 +281,7 @@ fn ttdelim_span() { .unwrap(); let tts: Vec<_> = match expr.kind { - ast::ExprKind::Mac(ref mac) => mac.args.inner_tokens().trees().collect(), + ast::ExprKind::MacCall(ref mac) => mac.args.inner_tokens().trees().collect(), _ => panic!("not a macro"), }; diff --git a/src/librustc_expand/placeholders.rs b/src/librustc_expand/placeholders.rs index 6bcb8f45f00..e1781f8636e 100644 --- a/src/librustc_expand/placeholders.rs +++ b/src/librustc_expand/placeholders.rs @@ -1,10 +1,10 @@ use crate::base::ExtCtxt; use crate::expand::{AstFragment, AstFragmentKind}; +use rustc_ast::ast; +use rustc_ast::mut_visit::*; +use rustc_ast::ptr::P; use rustc_span::source_map::{dummy_spanned, DUMMY_SP}; -use syntax::ast; -use syntax::mut_visit::*; -use syntax::ptr::P; use smallvec::{smallvec, SmallVec}; @@ -15,8 +15,8 @@ pub fn placeholder( id: ast::NodeId, vis: Option, ) -> AstFragment { - fn mac_placeholder() -> ast::Mac { - ast::Mac { + fn mac_placeholder() -> ast::MacCall { + ast::MacCall { path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, args: P(ast::MacArgs::Empty), prior_type_ascription: None, @@ -25,7 +25,6 @@ pub fn placeholder( let ident = ast::Ident::invalid(); let attrs = Vec::new(); - let generics = ast::Generics::default(); let vis = vis.unwrap_or_else(|| dummy_spanned(ast::VisibilityKind::Inherited)); let span = DUMMY_SP; let expr_placeholder = || { @@ -33,11 +32,11 @@ pub fn placeholder( id, span, attrs: ast::AttrVec::new(), - kind: ast::ExprKind::Mac(mac_placeholder()), + kind: ast::ExprKind::MacCall(mac_placeholder()), }) }; - let ty = || P(ast::Ty { id, kind: ast::TyKind::Mac(mac_placeholder()), span }); - let pat = || P(ast::Pat { id, kind: ast::PatKind::Mac(mac_placeholder()), span }); + let ty = || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span }); + let pat = || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span }); match kind { AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), @@ -48,7 +47,7 @@ pub fn placeholder( ident, vis, attrs, - kind: ast::ItemKind::Mac(mac_placeholder()), + kind: ast::ItemKind::MacCall(mac_placeholder()), tokens: None, })]), AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![P(ast::AssocItem { @@ -57,9 +56,7 @@ pub fn placeholder( ident, vis, attrs, - generics, - kind: ast::AssocItemKind::Macro(mac_placeholder()), - defaultness: ast::Defaultness::Final, + kind: ast::AssocItemKind::MacCall(mac_placeholder()), tokens: None, })]), AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![P(ast::AssocItem { @@ -68,9 +65,7 @@ pub fn placeholder( ident, vis, attrs, - generics, - kind: ast::AssocItemKind::Macro(mac_placeholder()), - defaultness: ast::Defaultness::Final, + kind: ast::AssocItemKind::MacCall(mac_placeholder()), tokens: None, })]), AstFragmentKind::ForeignItems => { @@ -80,19 +75,21 @@ pub fn placeholder( ident, vis, attrs, - kind: ast::ForeignItemKind::Macro(mac_placeholder()), + kind: ast::ForeignItemKind::MacCall(mac_placeholder()), tokens: None, })]) } - AstFragmentKind::Pat => { - AstFragment::Pat(P(ast::Pat { id, span, kind: ast::PatKind::Mac(mac_placeholder()) })) - } + AstFragmentKind::Pat => AstFragment::Pat(P(ast::Pat { + id, + span, + kind: ast::PatKind::MacCall(mac_placeholder()), + })), AstFragmentKind::Ty => { - AstFragment::Ty(P(ast::Ty { id, span, kind: ast::TyKind::Mac(mac_placeholder()) })) + AstFragment::Ty(P(ast::Ty { id, span, kind: ast::TyKind::MacCall(mac_placeholder()) })) } AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{ let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::AttrVec::new())); - ast::Stmt { id, span, kind: ast::StmtKind::Mac(mac) } + ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) } }]), AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm { attrs: Default::default(), @@ -244,7 +241,7 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { match item.kind { - ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(), + ast::ItemKind::MacCall(_) => return self.remove(item.id).make_items(), ast::ItemKind::MacroDef(_) => return smallvec![item], _ => {} } @@ -254,14 +251,14 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { match item.kind { - ast::AssocItemKind::Macro(_) => self.remove(item.id).make_trait_items(), + ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_trait_items(), _ => noop_flat_map_assoc_item(item, self), } } fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { match item.kind { - ast::AssocItemKind::Macro(_) => self.remove(item.id).make_impl_items(), + ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_impl_items(), _ => noop_flat_map_assoc_item(item, self), } } @@ -271,28 +268,28 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { item: P, ) -> SmallVec<[P; 1]> { match item.kind { - ast::ForeignItemKind::Macro(_) => self.remove(item.id).make_foreign_items(), + ast::ForeignItemKind::MacCall(_) => self.remove(item.id).make_foreign_items(), _ => noop_flat_map_foreign_item(item, self), } } fn visit_expr(&mut self, expr: &mut P) { match expr.kind { - ast::ExprKind::Mac(_) => *expr = self.remove(expr.id).make_expr(), + ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_expr(), _ => noop_visit_expr(expr, self), } } fn filter_map_expr(&mut self, expr: P) -> Option> { match expr.kind { - ast::ExprKind::Mac(_) => self.remove(expr.id).make_opt_expr(), + ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(), _ => noop_filter_map_expr(expr, self), } } fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { let (style, mut stmts) = match stmt.kind { - ast::StmtKind::Mac(mac) => (mac.1, self.remove(stmt.id).make_stmts()), + ast::StmtKind::MacCall(mac) => (mac.1, self.remove(stmt.id).make_stmts()), _ => return noop_flat_map_stmt(stmt, self), }; @@ -307,14 +304,14 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { fn visit_pat(&mut self, pat: &mut P) { match pat.kind { - ast::PatKind::Mac(_) => *pat = self.remove(pat.id).make_pat(), + ast::PatKind::MacCall(_) => *pat = self.remove(pat.id).make_pat(), _ => noop_visit_pat(pat, self), } } fn visit_ty(&mut self, ty: &mut P) { match ty.kind { - ast::TyKind::Mac(_) => *ty = self.remove(ty.id).make_ty(), + ast::TyKind::MacCall(_) => *ty = self.remove(ty.id).make_ty(), _ => noop_visit_ty(ty, self), } } @@ -333,12 +330,12 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { fn visit_mod(&mut self, module: &mut ast::Mod) { noop_visit_mod(module, self); module.items.retain(|item| match item.kind { - ast::ItemKind::Mac(_) if !self.cx.ecfg.keep_macs => false, // remove macro definitions + ast::ItemKind::MacCall(_) if !self.cx.ecfg.keep_macs => false, // remove macro definitions _ => true, }); } - fn visit_mac(&mut self, _mac: &mut ast::Mac) { + fn visit_mac(&mut self, _mac: &mut ast::MacCall) { // Do nothing. } } diff --git a/src/librustc_expand/proc_macro.rs b/src/librustc_expand/proc_macro.rs index cb6249e9369..cb9afa4cd4f 100644 --- a/src/librustc_expand/proc_macro.rs +++ b/src/librustc_expand/proc_macro.rs @@ -1,13 +1,13 @@ use crate::base::{self, *}; use crate::proc_macro_server; +use rustc_ast::ast::{self, ItemKind, MetaItemKind, NestedMetaItem}; +use rustc_ast::token; +use rustc_ast::tokenstream::{self, TokenStream}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, FatalError}; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; -use syntax::ast::{self, ItemKind, MetaItemKind, NestedMetaItem}; -use syntax::token; -use syntax::tokenstream::{self, TokenStream}; const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread; @@ -79,7 +79,7 @@ impl MultiItemModifier for ProcMacroDerive { span: Span, _meta_item: &ast::MetaItem, item: Annotatable, - ) -> Vec { + ) -> ExpandResult, Annotatable> { let item = match item { Annotatable::Arm(..) | Annotatable::Field(..) @@ -99,7 +99,7 @@ impl MultiItemModifier for ProcMacroDerive { "proc-macro derives may only be \ applied to a struct, enum, or union", ); - return Vec::new(); + return ExpandResult::Ready(Vec::new()); } }; match item.kind { @@ -110,7 +110,7 @@ impl MultiItemModifier for ProcMacroDerive { "proc-macro derives may only be \ applied to a struct, enum, or union", ); - return Vec::new(); + return ExpandResult::Ready(Vec::new()); } } @@ -158,7 +158,7 @@ impl MultiItemModifier for ProcMacroDerive { FatalError.raise(); } - items + ExpandResult::Ready(items) } } diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index a7397e576b1..5f21ff503d5 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -1,5 +1,9 @@ use crate::base::ExtCtxt; +use rustc_ast::ast; +use rustc_ast::token; +use rustc_ast::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; +use rustc_ast::util::comments; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::Diagnostic; @@ -8,10 +12,6 @@ use rustc_parse::{nt_to_tokenstream, parse_stream_from_source_str}; use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span}; -use syntax::ast; -use syntax::token; -use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; -use syntax::util::comments; use pm::bridge::{server, TokenTree}; use pm::{Delimiter, Level, LineColumn, Spacing}; @@ -54,13 +54,13 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> fn from_internal( ((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec), ) -> Self { - use syntax::token::*; + use rustc_ast::token::*; let joint = is_joint == Joint; let Token { kind, span } = match tree { tokenstream::TokenTree::Delimited(span, delim, tts) => { let delimiter = Delimiter::from_internal(delim); - return TokenTree::Group(Group { delimiter, stream: tts.into(), span }); + return TokenTree::Group(Group { delimiter, stream: tts, span }); } tokenstream::TokenTree::Token(token) => token, }; @@ -191,17 +191,13 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> impl ToInternal for TokenTree { fn to_internal(self) -> TokenStream { - use syntax::token::*; + use rustc_ast::token::*; let (ch, joint, span) = match self { TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span), TokenTree::Group(Group { delimiter, stream, span }) => { - return tokenstream::TokenTree::Delimited( - span, - delimiter.to_internal(), - stream.into(), - ) - .into(); + return tokenstream::TokenTree::Delimited(span, delimiter.to_internal(), stream) + .into(); } TokenTree::Ident(self::Ident { sym, is_raw, span }) => { return tokenstream::TokenTree::token(Ident(sym, is_raw), span).into(); @@ -209,7 +205,7 @@ impl ToInternal for TokenTree { TokenTree::Literal(self::Literal { lit: token::Lit { kind: token::Integer, symbol, suffix }, span, - }) if symbol.as_str().starts_with("-") => { + }) if symbol.as_str().starts_with('-') => { let minus = BinOp(BinOpToken::Minus); let symbol = Symbol::intern(&symbol.as_str()[1..]); let integer = TokenKind::lit(token::Integer, symbol, suffix); @@ -220,7 +216,7 @@ impl ToInternal for TokenTree { TokenTree::Literal(self::Literal { lit: token::Lit { kind: token::Float, symbol, suffix }, span, - }) if symbol.as_str().starts_with("-") => { + }) if symbol.as_str().starts_with('-') => { let minus = BinOp(BinOpToken::Minus); let symbol = Symbol::intern(&symbol.as_str()[1..]); let float = TokenKind::lit(token::Float, symbol, suffix); diff --git a/src/librustc_expand/tests.rs b/src/librustc_expand/tests.rs index 4ed60465f24..fbc49ddd562 100644 --- a/src/librustc_expand/tests.rs +++ b/src/librustc_expand/tests.rs @@ -1,10 +1,10 @@ +use rustc_ast::ast; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::with_default_globals; use rustc_parse::{new_parser_from_source_str, parser::Parser, source_file_to_stream}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{BytePos, MultiSpan, Span}; -use syntax::ast; -use syntax::tokenstream::TokenStream; -use syntax::with_default_globals; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::EmitterWriter; diff --git a/src/librustc_expand/tokenstream/tests.rs b/src/librustc_expand/tokenstream/tests.rs index 287c168f76a..db329f22d14 100644 --- a/src/librustc_expand/tokenstream/tests.rs +++ b/src/librustc_expand/tokenstream/tests.rs @@ -1,11 +1,11 @@ use crate::tests::string_to_stream; +use rustc_ast::ast::Name; +use rustc_ast::token; +use rustc_ast::tokenstream::{TokenStream, TokenStreamBuilder, TokenTree}; +use rustc_ast::with_default_globals; use rustc_span::{BytePos, Span}; use smallvec::smallvec; -use syntax::ast::Name; -use syntax::token; -use syntax::tokenstream::{TokenStream, TokenStreamBuilder, TokenTree}; -use syntax::with_default_globals; fn string_to_ts(string: &str) -> TokenStream { string_to_stream(string.to_owned()) diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 0082f4f1a6e..9f1fee8fc09 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -99,6 +99,9 @@ declare_features! ( // no-tracking-issue-start + /// Allows using `rustc_*` attributes (RFC 572). + (active, rustc_attrs, "1.0.0", None, None), + /// Allows using compiler's own crates. (active, rustc_private, "1.0.0", Some(27812), None), @@ -128,9 +131,6 @@ declare_features! ( /// Allows using `#[link_name="llvm.*"]`. (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), - /// Allows using `rustc_*` attributes (RFC 572). - (active, rustc_attrs, "1.0.0", Some(29642), None), - /// Allows using the `box $expr` syntax. (active, box_syntax, "1.0.0", Some(49733), None), @@ -289,9 +289,6 @@ declare_features! ( /// Permits specifying whether a function should permit unwinding or abort on unwind. (active, unwind_attributes, "1.4.0", Some(58760), None), - /// Allows `#[no_debug]`. - (active, no_debug, "1.5.0", Some(29721), None), - /// Allows attributes on expressions and non-item statements. (active, stmt_expr_attributes, "1.6.0", Some(15701), None), @@ -304,6 +301,11 @@ declare_features! ( /// Allows specialization of implementations (RFC 1210). (active, specialization, "1.7.0", Some(31844), None), + /// A minimal, sound subset of specialization intended to be used by the + /// standard library until the soundness issues with specialization + /// are fixed. + (active, min_specialization, "1.7.0", Some(31844), None), + /// Allows using `#[naked]` on functions. (active, naked_functions, "1.9.0", Some(32408), None), @@ -363,9 +365,6 @@ declare_features! ( /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), - /// Allows `#[doc(spotlight)]`. - (active, doc_spotlight, "1.22.0", Some(45040), None), - /// Allows `#[doc(include = "some-file")]`. (active, external_doc, "1.22.0", Some(44732), None), @@ -387,7 +386,7 @@ declare_features! ( /// Allows defining `trait X = A + B;` alias items. (active, trait_alias, "1.24.0", Some(41517), None), - /// Allows infering `'static` outlives requirements (RFC 2093). + /// Allows inferring `'static` outlives requirements (RFC 2093). (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), /// Allows accessing fields of unions inside `const` functions. @@ -552,6 +551,9 @@ declare_features! ( /// Allows the use of `no_sanitize` attribute. (active, no_sanitize, "1.42.0", Some(39699), None), + // Allows limiting the evaluation steps of const expressions + (active, const_eval_limit, "1.43.0", Some(67217), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs index 5c81f845595..aec441cb3bc 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -85,19 +85,13 @@ impl AttributeGate { /// A template that the attribute input must match. /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub struct AttributeTemplate { pub word: bool, pub list: Option<&'static str>, pub name_value_str: Option<&'static str>, } -impl AttributeTemplate { - pub fn only_word() -> Self { - Self { word: true, list: None, name_value_str: None } - } -} - /// A convenience macro for constructing attribute templates. /// E.g., `template!(Word, List: "description")` means that the attribute /// supports forms `#[attr]` and `#[attr(description)]`. @@ -175,7 +169,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Stable attributes: // ========================================================================== - // Condtional compilation: + // Conditional compilation: ungated!(cfg, Normal, template!(List: "predicate")), ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ...")), @@ -247,6 +241,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Limits: ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")), ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")), + gated!( + const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit, + experimental!(const_eval_limit) + ), // Entry point: ungated!(main, Normal, template!(Word)), @@ -511,16 +509,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ cfg_fn!(rustc_attrs), ), ), - ( - sym::no_debug, Whitelisted, template!(Word), - Gated( - Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None), - sym::no_debug, - "the `#[no_debug]` attribute was an experimental feature that has been \ - deprecated due to lack of demand", - cfg_fn!(no_debug) - ) - ), gated!( // Used in resolve: prelude_import, Whitelisted, template!(Word), @@ -544,6 +532,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_test_marker, Normal, template!(Word), "the `#[rustc_test_marker]` attribute is used internally to track tests", ), + rustc_attr!( + rustc_unsafe_specialization_marker, Normal, template!(Word), + "the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations" + ), + rustc_attr!( + rustc_specialization_trait, Normal, template!(Word), + "the `#[rustc_specialization_trait]` attribute is used to check specializations" + ), // ========================================================================== // Internal attributes, Testing: diff --git a/src/librustc_feature/removed.rs b/src/librustc_feature/removed.rs index e6ea093fe89..4e348054fbd 100644 --- a/src/librustc_feature/removed.rs +++ b/src/librustc_feature/removed.rs @@ -111,6 +111,8 @@ declare_features! ( /// Allows overlapping impls of marker traits. (removed, overlapping_marker_traits, "1.42.0", Some(29864), None, Some("removed in favor of `#![feature(marker_trait_attr)]`")), + /// Allows `#[no_debug]`. + (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")), // ------------------------------------------------------------------------- // feature-group-end: removed features // ------------------------------------------------------------------------- diff --git a/src/librustc_hir/Cargo.toml b/src/librustc_hir/Cargo.toml index cff64132532..872d114fb18 100644 --- a/src/librustc_hir/Cargo.toml +++ b/src/librustc_hir/Cargo.toml @@ -18,6 +18,6 @@ rustc_index = { path = "../librustc_index" } rustc_span = { path = "../librustc_span" } rustc_errors = { path = "../librustc_errors" } rustc_serialize = { path = "../libserialize", package = "serialize" } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } lazy_static = "1" smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_hir/def.rs b/src/librustc_hir/def.rs index 83e30d85c5a..696aa5c6f7d 100644 --- a/src/librustc_hir/def.rs +++ b/src/librustc_hir/def.rs @@ -1,10 +1,10 @@ use crate::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use crate::hir; +use rustc_ast::ast; +use rustc_ast::ast::NodeId; use rustc_macros::HashStable_Generic; use rustc_span::hygiene::MacroKind; -use syntax::ast; -use syntax::ast::NodeId; use std::fmt::Debug; @@ -72,7 +72,7 @@ pub enum DefKind { Static, /// Refers to the struct or enum variant's constructor. Ctor(CtorOf, CtorKind), - Method, + AssocFn, AssocConst, // Macro namespace @@ -107,7 +107,7 @@ impl DefKind { DefKind::Union => "union", DefKind::Trait => "trait", DefKind::ForeignTy => "foreign type", - DefKind::Method => "method", + DefKind::AssocFn => "associated function", DefKind::Const => "constant", DefKind::AssocConst => "associated constant", DefKind::TyParam => "type parameter", @@ -122,6 +122,7 @@ impl DefKind { DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocOpaqueTy + | DefKind::AssocFn | DefKind::Enum | DefKind::OpaqueTy => "an", DefKind::Macro(macro_kind) => macro_kind.article(), @@ -150,7 +151,7 @@ impl DefKind { | DefKind::ConstParam | DefKind::Static | DefKind::Ctor(..) - | DefKind::Method + | DefKind::AssocFn | DefKind::AssocConst => ns == Namespace::ValueNS, DefKind::Macro(..) => ns == Namespace::MacroNS, diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index c2ddaf7df31..0ef35b184e1 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -1,13 +1,19 @@ -use crate::def::{DefKind, Res}; +use crate::def::{DefKind, Namespace, Res}; use crate::def_id::DefId; crate use crate::hir_id::HirId; use crate::itemlikevisit; use crate::print; crate use BlockCheckMode::*; -crate use FunctionRetTy::*; +crate use FnRetTy::*; crate use UnsafeSource::*; +use rustc_ast::ast::{self, AsmDialect, CrateSugar, Ident, Name}; +use rustc_ast::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy}; +pub use rustc_ast::ast::{BorrowKind, ImplPolarity, IsAuto}; +pub use rustc_ast::ast::{CaptureBy, Movability, Mutability}; +use rustc_ast::node_id::NodeMap; +use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_errors::FatalError; @@ -16,13 +22,6 @@ use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use syntax::ast::{self, AsmDialect, CrateSugar, Ident, Name, NodeId}; -use syntax::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy}; -pub use syntax::ast::{BorrowKind, ImplPolarity, IsAuto}; -pub use syntax::ast::{CaptureBy, Movability, Mutability}; -use syntax::node_id::NodeMap; -use syntax::tokenstream::TokenStream; -use syntax::util::parser::ExprPrecedence; use smallvec::SmallVec; use std::collections::{BTreeMap, BTreeSet}; @@ -80,9 +79,9 @@ impl ParamName { } } - pub fn modern(&self) -> ParamName { + pub fn normalize_to_macros_2_0(&self) -> ParamName { match *self { - ParamName::Plain(ident) => ParamName::Plain(ident.modern()), + ParamName::Plain(ident) => ParamName::Plain(ident.normalize_to_macros_2_0()), param_name => param_name, } } @@ -152,9 +151,11 @@ impl LifetimeName { self == &LifetimeName::Static } - pub fn modern(&self) -> LifetimeName { + pub fn normalize_to_macros_2_0(&self) -> LifetimeName { match *self { - LifetimeName::Param(param_name) => LifetimeName::Param(param_name.modern()), + LifetimeName::Param(param_name) => { + LifetimeName::Param(param_name.normalize_to_macros_2_0()) + } lifetime_name => lifetime_name, } } @@ -298,6 +299,14 @@ impl GenericArg<'_> { _ => false, } } + + pub fn descr(&self) -> &'static str { + match self { + GenericArg::Lifetime(_) => "lifetime", + GenericArg::Type(_) => "type", + GenericArg::Const(_) => "constant", + } + } } #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] @@ -589,7 +598,7 @@ pub struct WhereEqPredicate<'hir> { pub rhs_ty: &'hir Ty<'hir>, } -#[derive(RustcEncodable, RustcDecodable, Debug)] +#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct ModuleItems { // Use BTreeSets here so items are in the same order as in the // list of all items in Crate @@ -598,17 +607,23 @@ pub struct ModuleItems { pub impl_items: BTreeSet, } +/// A type representing only the top-level module. +#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] +pub struct CrateItem<'hir> { + pub module: Mod<'hir>, + pub attrs: &'hir [Attribute], + pub span: Span, +} + /// The top-level data structure that stores the entire contents of /// the crate currently being compiled. /// -/// For more details, see the [rustc guide]. +/// For more details, see the [rustc dev guide]. /// -/// [rustc guide]: https://rust-lang.github.io/rustc-guide/hir.html +/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html #[derive(RustcEncodable, RustcDecodable, Debug)] pub struct Crate<'hir> { - pub module: Mod<'hir>, - pub attrs: &'hir [Attribute], - pub span: Span, + pub item: CrateItem<'hir>, pub exported_macros: &'hir [MacroDef<'hir>], // Attributes from non-exported macros, kept only for collecting the library feature list. pub non_exported_macro_attrs: &'hir [Attribute], @@ -635,6 +650,9 @@ pub struct Crate<'hir> { /// A list of modules written out in the order in which they /// appear in the crate. This includes the main crate module. pub modules: BTreeMap, + /// A list of proc macro HirIds, written out in the order in which + /// they are declared in the static array generated by proc_macro_harness. + pub proc_macros: Vec, } impl Crate<'hir> { @@ -668,15 +686,15 @@ impl Crate<'_> { where V: itemlikevisit::ItemLikeVisitor<'hir>, { - for (_, item) in &self.items { + for item in self.items.values() { visitor.visit_item(item); } - for (_, trait_item) in &self.trait_items { + for trait_item in self.trait_items.values() { visitor.visit_trait_item(trait_item); } - for (_, impl_item) in &self.impl_items { + for impl_item in self.impl_items.values() { visitor.visit_impl_item(impl_item); } } @@ -711,13 +729,12 @@ impl Crate<'_> { /// Not parsed directly, but created on macro import or `macro_rules!` expansion. #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub struct MacroDef<'hir> { - pub name: Name, + pub ident: Ident, pub vis: Visibility<'hir>, pub attrs: &'hir [Attribute], pub hir_id: HirId, pub span: Span, - pub body: TokenStream, - pub legacy: bool, + pub ast: ast::MacroDef, } /// A block of statements `{ .. }`, which may have a label (in this case the @@ -1493,7 +1510,7 @@ pub fn is_range_literal(sm: &SourceMap, expr: &Expr<'_>) -> bool { let end_point = sm.end_point(*span); if let Ok(end_string) = sm.span_to_snippet(end_point) { - !(end_string.ends_with("}") || end_string.ends_with(")")) + !(end_string.ends_with('}') || end_string.ends_with(')')) } else { false } @@ -1839,7 +1856,7 @@ pub struct TraitItem<'hir> { /// Represents a trait method's body (or just argument names). #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] -pub enum TraitMethod<'hir> { +pub enum TraitFn<'hir> { /// No default body in the trait, just a signature. Required(&'hir [Ident]), @@ -1852,8 +1869,8 @@ pub enum TraitMethod<'hir> { pub enum TraitItemKind<'hir> { /// An associated constant with an optional value (otherwise `impl`s must contain a value). Const(&'hir Ty<'hir>, Option), - /// A method with an optional body. - Method(FnSig<'hir>, TraitMethod<'hir>), + /// An associated function with an optional body. + Fn(FnSig<'hir>, TraitFn<'hir>), /// An associated type with (possibly empty) bounds and optional concrete /// type. Type(GenericBounds<'hir>, Option<&'hir Ty<'hir>>), @@ -1886,14 +1903,23 @@ pub enum ImplItemKind<'hir> { /// An associated constant of the given type, set to the constant result /// of the expression. Const(&'hir Ty<'hir>, BodyId), - /// A method implementation with the given signature and body. - Method(FnSig<'hir>, BodyId), + /// An associated function implementation with the given signature and body. + Fn(FnSig<'hir>, BodyId), /// An associated type. TyAlias(&'hir Ty<'hir>), /// An associated `type = impl Trait`. OpaqueTy(GenericBounds<'hir>), } +impl ImplItemKind<'_> { + pub fn namespace(&self) -> Namespace { + match self { + ImplItemKind::OpaqueTy(..) | ImplItemKind::TyAlias(..) => Namespace::TypeNS, + ImplItemKind::Const(..) | ImplItemKind::Fn(..) => Namespace::ValueNS, + } + } +} + // The name of the associated type for `Fn` return types. pub const FN_OUTPUT_NAME: Symbol = sym::Output; @@ -1990,6 +2016,8 @@ pub enum OpaqueTyOrigin { FnReturn, /// `async fn` AsyncFn, + /// Impl trait in bindings, consts, statics, bounds. + Misc, } /// The various kinds of types recognized by the compiler. @@ -2077,7 +2105,7 @@ pub struct FnDecl<'hir> { /// /// Additional argument data is stored in the function's [body](Body::parameters). pub inputs: &'hir [Ty<'hir>], - pub output: FunctionRetTy<'hir>, + pub output: FnRetTy<'hir>, pub c_variadic: bool, /// Does the function have an implicit self? pub implicit_self: ImplicitSelfKind, @@ -2143,7 +2171,7 @@ impl Defaultness { } #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] -pub enum FunctionRetTy<'hir> { +pub enum FnRetTy<'hir> { /// Return type is not specified. /// /// Functions default to `()` and @@ -2154,7 +2182,7 @@ pub enum FunctionRetTy<'hir> { Return(&'hir Ty<'hir>), } -impl fmt::Display for FunctionRetTy<'_> { +impl fmt::Display for FnRetTy<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Return(ref ty) => print::to_string(print::NO_ANN, |s| s.print_type(ty)).fmt(f), @@ -2163,7 +2191,7 @@ impl fmt::Display for FunctionRetTy<'_> { } } -impl FunctionRetTy<'_> { +impl FnRetTy<'_> { pub fn span(&self) -> Span { match *self { Self::DefaultReturn(span) => span, @@ -2486,16 +2514,16 @@ pub enum ItemKind<'hir> { } impl ItemKind<'_> { - pub fn descriptive_variant(&self) -> &str { + pub fn descr(&self) -> &str { match *self { ItemKind::ExternCrate(..) => "extern crate", - ItemKind::Use(..) => "use", + ItemKind::Use(..) => "`use` import", ItemKind::Static(..) => "static item", ItemKind::Const(..) => "constant item", ItemKind::Fn(..) => "function", ItemKind::Mod(..) => "module", - ItemKind::ForeignMod(..) => "foreign module", - ItemKind::GlobalAsm(..) => "global asm", + ItemKind::ForeignMod(..) => "extern block", + ItemKind::GlobalAsm(..) => "global asm item", ItemKind::TyAlias(..) => "type alias", ItemKind::OpaqueTy(..) => "opaque type", ItemKind::Enum(..) => "enum", @@ -2503,7 +2531,7 @@ impl ItemKind<'_> { ItemKind::Union(..) => "union", ItemKind::Trait(..) => "trait", ItemKind::TraitAlias(..) => "trait alias", - ItemKind::Impl { .. } => "impl", + ItemKind::Impl { .. } => "implementation", } } @@ -2608,19 +2636,30 @@ pub type CaptureModeMap = NodeMap; // has length > 0 if the trait is found through an chain of imports, starting with the // import/use statement in the scope where the trait is used. #[derive(Clone, Debug)] -pub struct TraitCandidate { +pub struct TraitCandidate { pub def_id: DefId, - pub import_ids: SmallVec<[NodeId; 1]>, + pub import_ids: SmallVec<[ID; 1]>, +} + +impl TraitCandidate { + pub fn map_import_ids(self, f: F) -> TraitCandidate + where + F: Fn(ID) -> T, + { + let TraitCandidate { def_id, import_ids } = self; + let import_ids = import_ids.into_iter().map(f).collect(); + TraitCandidate { def_id, import_ids } + } } // Trait method resolution -pub type TraitMap = NodeMap>; +pub type TraitMap = NodeMap>>; // Map from the NodeId of a glob import to a list of items which are actually // imported. pub type GlobMap = NodeMap>; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum Node<'hir> { Param(&'hir Param<'hir>), Item(&'hir Item<'hir>), @@ -2650,7 +2689,7 @@ pub enum Node<'hir> { GenericParam(&'hir GenericParam<'hir>), Visibility(&'hir Visibility<'hir>), - Crate, + Crate(&'hir CrateItem<'hir>), } impl Node<'_> { @@ -2666,8 +2705,8 @@ impl Node<'_> { pub fn fn_decl(&self) -> Option<&FnDecl<'_>> { match self { - Node::TraitItem(TraitItem { kind: TraitItemKind::Method(fn_sig, _), .. }) - | Node::ImplItem(ImplItem { kind: ImplItemKind::Method(fn_sig, _), .. }) + Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) + | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl), Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { Some(fn_decl) diff --git a/src/librustc_hir/hir_id.rs b/src/librustc_hir/hir_id.rs index 6d2ec445763..1c7987e965f 100644 --- a/src/librustc_hir/hir_id.rs +++ b/src/librustc_hir/hir_id.rs @@ -1,9 +1,8 @@ -use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX}; -use rustc_serialize::{self, Decodable, Decoder, Encodable, Encoder}; +use crate::def_id::{LocalDefId, CRATE_DEF_INDEX}; use std::fmt; /// Uniquely identifies a node in the HIR of the current crate. It is -/// composed of the `owner`, which is the `DefIndex` of the directly enclosing +/// composed of the `owner`, which is the `LocalDefId` of the directly enclosing /// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"), /// and the `local_id` which is unique within the given owner. /// @@ -12,41 +11,12 @@ use std::fmt; /// the `local_id` part of the `HirId` changing, which is a very useful property in /// incremental compilation where we have to persist things through changes to /// the code base. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)] pub struct HirId { - pub owner: DefIndex, + pub owner: LocalDefId, pub local_id: ItemLocalId, } -impl HirId { - pub fn owner_def_id(self) -> DefId { - DefId::local(self.owner) - } - - pub fn owner_local_def_id(self) -> LocalDefId { - LocalDefId::from_def_id(DefId::local(self.owner)) - } -} - -impl rustc_serialize::UseSpecializedEncodable for HirId { - fn default_encode(&self, s: &mut S) -> Result<(), S::Error> { - let HirId { owner, local_id } = *self; - - owner.encode(s)?; - local_id.encode(s)?; - Ok(()) - } -} - -impl rustc_serialize::UseSpecializedDecodable for HirId { - fn default_decode(d: &mut D) -> Result { - let owner = DefIndex::decode(d)?; - let local_id = ItemLocalId::decode(d)?; - - Ok(HirId { owner, local_id }) - } -} - impl fmt::Display for HirId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) @@ -70,9 +40,12 @@ rustc_index::newtype_index! { rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId); /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`. -pub const CRATE_HIR_ID: HirId = - HirId { owner: CRATE_DEF_INDEX, local_id: ItemLocalId::from_u32_const(0) }; +pub const CRATE_HIR_ID: HirId = HirId { + owner: LocalDefId { local_def_index: CRATE_DEF_INDEX }, + local_id: ItemLocalId::from_u32(0), +}; -pub const DUMMY_HIR_ID: HirId = HirId { owner: CRATE_DEF_INDEX, local_id: DUMMY_ITEM_LOCAL_ID }; +pub const DUMMY_HIR_ID: HirId = + HirId { owner: LocalDefId { local_def_index: CRATE_DEF_INDEX }, local_id: DUMMY_ITEM_LOCAL_ID }; pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX; diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs index 539a0eee0e3..316b31f0698 100644 --- a/src/librustc_hir/intravisit.rs +++ b/src/librustc_hir/intravisit.rs @@ -34,9 +34,9 @@ use crate::hir::*; use crate::hir_id::CRATE_HIR_ID; use crate::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor}; +use rustc_ast::ast::{Attribute, Ident, Label, Name}; +use rustc_ast::walk_list; use rustc_span::Span; -use syntax::ast::{Attribute, Ident, Label, Name}; -use syntax::walk_list; pub struct DeepVisitor<'v, V> { visitor: &'v mut V, @@ -127,6 +127,25 @@ pub trait Map<'hir> { fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir>; } +/// An erased version of `Map<'hir>`, using dynamic dispatch. +/// NOTE: This type is effectively only usable with `NestedVisitorMap::None`. +pub struct ErasedMap<'hir>(&'hir dyn Map<'hir>); + +impl<'hir> Map<'hir> for ErasedMap<'hir> { + fn body(&self, id: BodyId) -> &'hir Body<'hir> { + self.0.body(id) + } + fn item(&self, id: HirId) -> &'hir Item<'hir> { + self.0.item(id) + } + fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> { + self.0.trait_item(id) + } + fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> { + self.0.impl_item(id) + } +} + /// Specifies what nested things a visitor wants to visit. The most /// common choice is `OnlyBodies`, which will cause the visitor to /// visit fn bodies for fns that it encounters, but skip over nested @@ -134,7 +153,7 @@ pub trait Map<'hir> { /// /// See the comments on `ItemLikeVisitor` for more details on the overall /// visit strategy. -pub enum NestedVisitorMap<'this, M> { +pub enum NestedVisitorMap { /// Do not visit any nested things. When you add a new /// "non-nested" thing, you will want to audit such uses to see if /// they remain valid. @@ -151,20 +170,20 @@ pub enum NestedVisitorMap<'this, M> { /// to use `visit_all_item_likes()` as an outer loop, /// and to have the visitor that visits the contents of each item /// using this setting. - OnlyBodies(&'this M), + OnlyBodies(M), /// Visits all nested things, including item-likes. /// /// **This is an unusual choice.** It is used when you want to /// process everything within their lexical context. Typically you /// kick off the visit by doing `walk_krate()`. - All(&'this M), + All(M), } -impl<'this, M> NestedVisitorMap<'this, M> { +impl NestedVisitorMap { /// Returns the map to use for an "intra item-like" thing (if any). /// E.g., function body. - fn intra(self) -> Option<&'this M> { + fn intra(self) -> Option { match self { NestedVisitorMap::None => None, NestedVisitorMap::OnlyBodies(map) => Some(map), @@ -174,7 +193,7 @@ impl<'this, M> NestedVisitorMap<'this, M> { /// Returns the map to use for an "item-like" thing (if any). /// E.g., item, impl-item. - fn inter(self) -> Option<&'this M> { + fn inter(self) -> Option { match self { NestedVisitorMap::None => None, NestedVisitorMap::OnlyBodies(_) => None, @@ -221,7 +240,7 @@ pub trait Visitor<'v>: Sized { /// `panic!()`. This way, if a new `visit_nested_XXX` variant is /// added in the future, we will see the panic in your code and /// fix it appropriately. - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map>; + fn nested_visit_map(&mut self) -> NestedVisitorMap; /// Invoked when a nested item is encountered. By default does /// nothing unless you override `nested_visit_map` to return other than @@ -284,7 +303,7 @@ pub trait Visitor<'v>: Sized { /// If you use this, you probably don't want to process the /// contents of nested item-like things, since the outer loop will /// visit them as well. - fn as_deep_visitor<'s>(&'s mut self) -> DeepVisitor<'s, Self> { + fn as_deep_visitor(&mut self) -> DeepVisitor<'_, Self> { DeepVisitor::new(self) } @@ -438,14 +457,14 @@ pub trait Visitor<'v>: Sized { /// Walks the contents of a crate. See also `Crate::visit_all_items`. pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate<'v>) { - visitor.visit_mod(&krate.module, krate.span, CRATE_HIR_ID); - walk_list!(visitor, visit_attribute, krate.attrs); + visitor.visit_mod(&krate.item.module, krate.item.span, CRATE_HIR_ID); + walk_list!(visitor, visit_attribute, krate.item.attrs); walk_list!(visitor, visit_macro_def, krate.exported_macros); } pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef<'v>) { visitor.visit_id(macro_def.hir_id); - visitor.visit_name(macro_def.span, macro_def.name); + visitor.visit_ident(macro_def.ident); walk_list!(visitor, visit_attribute, macro_def.attrs); } @@ -865,8 +884,8 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>( } } -pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy<'v>) { - if let FunctionRetTy::Return(ref output_ty) = *ret_ty { +pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) { + if let FnRetTy::Return(ref output_ty) = *ret_ty { visitor.visit_ty(output_ty) } } @@ -911,14 +930,14 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai visitor.visit_ty(ty); walk_list!(visitor, visit_nested_body, default); } - TraitItemKind::Method(ref sig, TraitMethod::Required(param_names)) => { + TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => { visitor.visit_id(trait_item.hir_id); visitor.visit_fn_decl(&sig.decl); for ¶m_name in param_names { visitor.visit_ident(param_name); } } - TraitItemKind::Method(ref sig, TraitMethod::Provided(body_id)) => { + TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => { visitor.visit_fn( FnKind::Method(trait_item.ident, sig, None, &trait_item.attrs), &sig.decl, @@ -968,7 +987,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt visitor.visit_ty(ty); visitor.visit_nested_body(body); } - ImplItemKind::Method(ref sig, body_id) => { + ImplItemKind::Fn(ref sig, body_id) => { visitor.visit_fn( FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis), &impl_item.attrs), &sig.decl, diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 4cb6b7d943c..1dd7e224da8 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -12,12 +12,12 @@ pub use self::LangItem::*; use crate::def_id::DefId; use crate::Target; +use rustc_ast::ast; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable_Generic; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; -use syntax::ast; use lazy_static::lazy_static; @@ -240,7 +240,6 @@ language_item_table! { StartFnLangItem, "start", start_fn, Target::Fn; EhPersonalityLangItem, "eh_personality", eh_personality, Target::Fn; - EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume, Target::Fn; EhCatchTypeinfoLangItem, "eh_catch_typeinfo", eh_catch_typeinfo, Target::Static; OwnedBoxLangItem, "owned_box", owned_box, Target::Struct; diff --git a/src/librustc_hir/lib.rs b/src/librustc_hir/lib.rs index d958dfc681b..fa5c72b060d 100644 --- a/src/librustc_hir/lib.rs +++ b/src/librustc_hir/lib.rs @@ -1,9 +1,11 @@ -//! HIR datatypes. See the [rustc guide] for more info. +//! HIR datatypes. See the [rustc dev guide] for more info. //! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/hir.html +//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html #![feature(crate_visibility_modifier)] +#![feature(const_if_match)] #![feature(const_fn)] // For the unsizing cast on `&[]` +#![feature(const_panic)] #![feature(in_band_lifetimes)] #![feature(specialization)] #![recursion_limit = "256"] diff --git a/src/librustc_hir/pat_util.rs b/src/librustc_hir/pat_util.rs index 6bca45b4f83..0b9ffdf21fe 100644 --- a/src/librustc_hir/pat_util.rs +++ b/src/librustc_hir/pat_util.rs @@ -1,8 +1,8 @@ use crate::def::{CtorOf, DefKind, Res}; use crate::def_id::DefId; use crate::hir::{self, HirId, PatKind}; +use rustc_ast::ast; use rustc_span::Span; -use syntax::ast; use std::iter::{Enumerate, ExactSizeIterator}; diff --git a/src/librustc_hir/print.rs b/src/librustc_hir/print.rs index e49f99fb717..4e9618b7676 100644 --- a/src/librustc_hir/print.rs +++ b/src/librustc_hir/print.rs @@ -1,12 +1,12 @@ +use rustc_ast::ast; +use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, Breaks}; -use rustc_ast_pretty::pprust::{self, Comments, PrintState}; +use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_span::source_map::{SourceMap, Spanned}; -use rustc_span::symbol::kw; +use rustc_span::symbol::{kw, IdentPrinter}; use rustc_span::{self, BytePos, FileName}; use rustc_target::spec::abi::Abi; -use syntax::ast; -use syntax::util::parser::{self, AssocOp, Fixity}; use crate::hir; use crate::hir::{GenericArg, GenericParam, GenericParamKind, Node}; @@ -102,7 +102,7 @@ impl<'a> State<'a> { Node::Ctor(..) => panic!("cannot print isolated Ctor"), Node::Local(a) => self.print_local_decl(&a), Node::MacroDef(_) => panic!("cannot print MacroDef"), - Node::Crate => panic!("cannot print Crate"), + Node::Crate(..) => panic!("cannot print Crate"), } } } @@ -126,7 +126,7 @@ impl<'a> PrintState<'a> for State<'a> { } fn print_ident(&mut self, ident: ast::Ident) { - self.s.word(pprust::ast_ident_to_string(ident, ident.is_raw_guess())); + self.s.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string()); self.ann.post(self, AnnNode::Name(&ident.name)) } @@ -140,30 +140,30 @@ pub const INDENT_UNIT: usize = 4; /// Requires you to pass an input filename and reader so that /// it can scan the input text for comments to copy forward. pub fn print_crate<'a>( - cm: &'a SourceMap, + sm: &'a SourceMap, krate: &hir::Crate<'_>, filename: FileName, input: String, ann: &'a dyn PpAnn, ) -> String { - let mut s = State::new_from_input(cm, filename, input, ann); + let mut s = State::new_from_input(sm, filename, input, ann); // When printing the AST, we sometimes need to inject `#[no_std]` here. // Since you can't compile the HIR, it's not necessary. - s.print_mod(&krate.module, &krate.attrs); + s.print_mod(&krate.item.module, &krate.item.attrs); s.print_remaining_comments(); s.s.eof() } impl<'a> State<'a> { pub fn new_from_input( - cm: &'a SourceMap, + sm: &'a SourceMap, filename: FileName, input: String, ann: &'a dyn PpAnn, ) -> State<'a> { - State { s: pp::mk_printer(), comments: Some(Comments::new(cm, filename, input)), ann } + State { s: pp::mk_printer(), comments: Some(Comments::new(sm, filename, input)), ann } } } @@ -652,7 +652,7 @@ impl<'a> State<'a> { self.word_nbsp("const"); } - if let hir::ImplPolarity::Negative = polarity { + if let hir::ImplPolarity::Negative(_) = polarity { self.s.word("!"); } @@ -886,13 +886,13 @@ impl<'a> State<'a> { Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited }; self.print_associated_const(ti.ident, &ty, default, &vis); } - hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref arg_names)) => { + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref arg_names)) => { let vis = Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited }; self.print_method_sig(ti.ident, sig, &ti.generics, &vis, arg_names, None); self.s.word(";"); } - hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => { + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let vis = Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Inherited }; self.head(""); @@ -925,7 +925,7 @@ impl<'a> State<'a> { hir::ImplItemKind::Const(ref ty, expr) => { self.print_associated_const(ii.ident, &ty, Some(expr), &ii.vis); } - hir::ImplItemKind::Method(ref sig, body) => { + hir::ImplItemKind::Fn(ref sig, body) => { self.head(""); self.print_method_sig(ii.ident, sig, &ii.generics, &ii.vis, &[], Some(body)); self.nbsp(); diff --git a/src/librustc_hir/stable_hash_impls.rs b/src/librustc_hir/stable_hash_impls.rs index e8407b53701..996b3108969 100644 --- a/src/librustc_hir/stable_hash_impls.rs +++ b/src/librustc_hir/stable_hash_impls.rs @@ -1,12 +1,18 @@ -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; -use crate::hir::{BodyId, Expr, ImplItemId, ItemId, Mod, TraitItemId, Ty, VisibilityKind}; -use crate::hir_id::HirId; +use crate::hir::{ + BodyId, Expr, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem, TraitItemId, Ty, + VisibilityKind, +}; +use crate::hir_id::{HirId, ItemLocalId}; +use rustc_span::def_id::{DefPathHash, LocalDefId}; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in librustc. -pub trait HashStableContext: syntax::HashStableContext + rustc_target::HashStableContext { +pub trait HashStableContext: + rustc_ast::HashStableContext + rustc_target::HashStableContext +{ fn hash_hir_id(&mut self, _: HirId, hasher: &mut StableHasher); fn hash_body_id(&mut self, _: BodyId, hasher: &mut StableHasher); fn hash_reference_to_item(&mut self, _: HirId, hasher: &mut StableHasher); @@ -14,6 +20,36 @@ pub trait HashStableContext: syntax::HashStableContext + rustc_target::HashStabl fn hash_hir_expr(&mut self, _: &Expr<'_>, hasher: &mut StableHasher); fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher); fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher); + fn hash_hir_item_like(&mut self, f: F); + fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash; +} + +impl ToStableHashKey for HirId { + type KeyType = (DefPathHash, ItemLocalId); + + #[inline] + fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) { + let def_path_hash = hcx.local_def_path_hash(self.owner); + (def_path_hash, self.local_id) + } +} + +impl ToStableHashKey for TraitItemId { + type KeyType = (DefPathHash, ItemLocalId); + + #[inline] + fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) { + self.hir_id.to_stable_hash_key(hcx) + } +} + +impl ToStableHashKey for ImplItemId { + type KeyType = (DefPathHash, ItemLocalId); + + #[inline] + fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) { + self.hir_id.to_stable_hash_key(hcx) + } } impl HashStable for HirId { @@ -76,3 +112,56 @@ impl HashStable for VisibilityKind<'_> hcx.hash_hir_visibility_kind(self, hasher) } } + +impl HashStable for TraitItem<'_> { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + let TraitItem { hir_id: _, ident, ref attrs, ref generics, ref kind, span } = *self; + + hcx.hash_hir_item_like(|hcx| { + ident.name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + generics.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl HashStable for ImplItem<'_> { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + let ImplItem { + hir_id: _, + ident, + ref vis, + defaultness, + ref attrs, + ref generics, + ref kind, + span, + } = *self; + + hcx.hash_hir_item_like(|hcx| { + ident.name.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + defaultness.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + generics.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl HashStable for Item<'_> { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + let Item { ident, ref attrs, hir_id: _, ref kind, ref vis, span } = *self; + + hcx.hash_hir_item_like(|hcx| { + ident.name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + kind.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} diff --git a/src/librustc_hir/target.rs b/src/librustc_hir/target.rs index 501976fc3cb..3a4485a1b17 100644 --- a/src/librustc_hir/target.rs +++ b/src/librustc_hir/target.rs @@ -105,10 +105,10 @@ impl Target { pub fn from_trait_item(trait_item: &TraitItem<'_>) -> Target { match trait_item.kind { TraitItemKind::Const(..) => Target::AssocConst, - TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => { + TraitItemKind::Fn(_, hir::TraitFn::Required(_)) => { Target::Method(MethodKind::Trait { body: false }) } - TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => { + TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => { Target::Method(MethodKind::Trait { body: true }) } TraitItemKind::Type(..) => Target::AssocTy, diff --git a/src/librustc_hir/weak_lang_items.rs b/src/librustc_hir/weak_lang_items.rs index 79182caae8c..c0560eb8d45 100644 --- a/src/librustc_hir/weak_lang_items.rs +++ b/src/librustc_hir/weak_lang_items.rs @@ -3,9 +3,9 @@ use crate::def_id::DefId; use crate::{lang_items, LangItem, LanguageItems}; +use rustc_ast::ast; use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::{sym, Symbol}; -use syntax::ast; use lazy_static::lazy_static; @@ -43,6 +43,5 @@ impl LanguageItems { weak_lang_items! { panic_impl, PanicImplLangItem, rust_begin_unwind; eh_personality, EhPersonalityLangItem, rust_eh_personality; - eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume; oom, OomLangItem, rust_oom; } diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index 09b33a6c83d..eddfb81ea8b 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -17,7 +17,7 @@ rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_hir = { path = "../librustc_hir" } rustc_serialize = { path = "../libserialize", package = "serialize" } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } rustc_fs_util = { path = "../librustc_fs_util" } rustc_session = { path = "../librustc_session" } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 51cc091b6c0..a7dccaf974b 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -38,6 +38,7 @@ use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter}; use rustc::dep_graph::{DepGraphQuery, DepKind, DepNode}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; +use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::implementation::{Direction, NodeIndex, INCOMING, OUTGOING}; use rustc_hir as hir; @@ -45,7 +46,6 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_span::symbol::sym; use rustc_span::Span; -use syntax::ast; use std::env; use std::fs::{self, File}; @@ -68,7 +68,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) { let (if_this_changed, then_this_would_need) = { let mut visitor = IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] }; - visitor.process_attrs(hir::CRATE_HIR_ID, &tcx.hir().krate().attrs); + visitor.process_attrs(hir::CRATE_HIR_ID, &tcx.hir().krate().item.attrs); tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); (visitor.if_this_changed, visitor.then_this_would_need) }; @@ -120,7 +120,7 @@ impl IfThisChanged<'tcx> { if attr.check_name(sym::rustc_if_this_changed) { let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { - None => def_path_hash.to_dep_node(DepKind::Hir), + None => DepNode::from_def_path_hash(def_path_hash, DepKind::hir_owner), Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) { Ok(n) => n, Err(()) => { @@ -162,8 +162,8 @@ impl IfThisChanged<'tcx> { impl Visitor<'tcx> for IfThisChanged<'tcx> { type Map = Map<'tcx>; - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir()) + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.tcx.hir()) } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index 70abb38278a..54d7e0ece50 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -23,11 +23,11 @@ use rustc::mir::mono::CodegenUnitNameBuilder; use rustc::ty::TyCtxt; +use rustc_ast::ast; use rustc_hir::def_id::LOCAL_CRATE; use rustc_session::cgu_reuse_tracker::*; use rustc_span::symbol::{sym, Symbol}; use std::collections::BTreeSet; -use syntax::ast; pub fn assert_module_sources(tcx: TyCtxt<'_>) { tcx.dep_graph.with_ignore(|| { @@ -44,7 +44,7 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) { let ams = AssertModuleSource { tcx, available_cgus }; - for attr in tcx.hir().krate().attrs { + for attr in tcx.hir().krate().item.attrs { ams.check_attr(attr); } }) @@ -81,10 +81,7 @@ impl AssertModuleSource<'tcx> { if !self.tcx.sess.opts.debugging_opts.query_dep_graph { self.tcx.sess.span_fatal( attr.span, - &format!( - "found CGU-reuse attribute but `-Zquery-dep-graph` \ - was not specified" - ), + "found CGU-reuse attribute but `-Zquery-dep-graph` was not specified", ); } @@ -107,7 +104,7 @@ impl AssertModuleSource<'tcx> { } // Split of the "special suffix" if there is one. - let (user_path, cgu_special_suffix) = if let Some(index) = user_path.rfind(".") { + let (user_path, cgu_special_suffix) = if let Some(index) = user_path.rfind('.') { (&user_path[..index], Some(&user_path[index + 1..])) } else { (&user_path[..], None) diff --git a/src/librustc_incremental/persist/README.md b/src/librustc_incremental/persist/README.md index 8131d2840b4..b01fe219e1e 100644 --- a/src/librustc_incremental/persist/README.md +++ b/src/librustc_incremental/persist/README.md @@ -1,3 +1,3 @@ -For info on how the incremental compilation works, see the [rustc guide]. +For info on how the incremental compilation works, see the [rustc dev guide]. -[rustc guide]: https://rust-lang.github.io/rustc-guide/query.html +[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/query.html diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index c5e74868bda..df5fd110db9 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -16,6 +16,7 @@ use rustc::dep_graph::{label_strs, DepNode}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; +use rustc_ast::ast::{self, Attribute, NestedMetaItem}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; @@ -28,7 +29,6 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use std::iter::FromIterator; use std::vec::Vec; -use syntax::ast::{self, Attribute, NestedMetaItem}; const EXCEPT: Symbol = sym::except; const LABEL: Symbol = sym::label; @@ -53,9 +53,9 @@ const BASE_FN: &[&str] = &[ /// DepNodes for Hir, which is pretty much everything const BASE_HIR: &[&str] = &[ - // Hir and HirBody should be computed for all nodes - label_strs::Hir, - label_strs::HirBody, + // hir_owner and hir_owner_items should be computed for all nodes + label_strs::hir_owner, + label_strs::hir_owner_items, ]; /// `impl` implementation of struct/trait @@ -78,7 +78,7 @@ const BASE_STRUCT: &[&str] = const BASE_TRAIT_DEF: &[&str] = &[ label_strs::associated_item_def_ids, label_strs::generics_of, - label_strs::is_object_safe, + label_strs::object_safety_violations, label_strs::predicates_of, label_strs::specialization_graph_of, label_strs::trait_def, @@ -168,7 +168,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { // Note that we cannot use the existing "unused attribute"-infrastructure // here, since that is running before codegen. This is also the reason why - // all codegen-specific attributes are `Whitelisted` in syntax::feature_gate. + // all codegen-specific attributes are `Whitelisted` in rustc_ast::feature_gate. all_attrs.report_unchecked_attrs(&dirty_clean_visitor.checked_attrs); }) } @@ -328,12 +328,12 @@ impl DirtyCleanVisitor<'tcx> { } } HirNode::TraitItem(item) => match item.kind { - TraitItemKind::Method(..) => ("Node::TraitItem", LABELS_FN_IN_TRAIT), + TraitItemKind::Fn(..) => ("Node::TraitItem", LABELS_FN_IN_TRAIT), TraitItemKind::Const(..) => ("NodeTraitConst", LABELS_CONST_IN_TRAIT), TraitItemKind::Type(..) => ("NodeTraitType", LABELS_CONST_IN_TRAIT), }, HirNode::ImplItem(item) => match item.kind { - ImplItemKind::Method(..) => ("Node::ImplItem", LABELS_FN_IN_IMPL), + ImplItemKind::Fn(..) => ("Node::ImplItem", LABELS_FN_IN_IMPL), ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL), ImplItemKind::TyAlias(..) => ("NodeImplType", LABELS_CONST_IN_IMPL), ImplItemKind::OpaqueTy(..) => ("NodeImplType", LABELS_CONST_IN_IMPL), @@ -343,7 +343,8 @@ impl DirtyCleanVisitor<'tcx> { &format!("clean/dirty auto-assertions not yet defined for {:?}", node), ), }; - let labels = Labels::from_iter(labels.iter().flat_map(|s| s.iter().map(|l| l.to_string()))); + let labels = + Labels::from_iter(labels.iter().flat_map(|s| s.iter().map(|l| (*l).to_string()))); (name, labels) } @@ -537,10 +538,7 @@ impl FindAllAttrs<'tcx> { if !checked_attrs.contains(&attr.id) { self.tcx.sess.span_err( attr.span, - &format!( - "found unchecked \ - `#[rustc_dirty]` / `#[rustc_clean]` attribute" - ), + "found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute", ); } } @@ -550,8 +548,8 @@ impl FindAllAttrs<'tcx> { impl intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> { type Map = Map<'tcx>; - fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, Self::Map> { - intravisit::NestedVisitorMap::All(&self.tcx.hir()) + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::All(self.tcx.hir()) } fn visit_attribute(&mut self, attr: &'tcx Attribute) { diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs index 5c72b049d97..048a81b81ba 100644 --- a/src/librustc_incremental/persist/file_format.rs +++ b/src/librustc_incremental/persist/file_format.rs @@ -14,8 +14,8 @@ use std::fs; use std::io::{self, Read}; use std::path::Path; -use rustc::session::config::nightly_options; use rustc_serialize::opaque::Encoder; +use rustc_session::config::nightly_options; /// The first few bytes of files generated by incremental compilation. const FILE_MAGIC: &[u8] = b"RSIC"; diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index ba20006d73c..4926f726f35 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -103,11 +103,11 @@ //! unsupported file system and emit a warning in that case. This is not yet //! implemented. -use rustc::session::{CrateDisambiguator, Session}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::svh::Svh; use rustc_data_structures::{base_n, flock}; use rustc_fs_util::{link_or_copy, LinkOrCopy}; +use rustc_session::{CrateDisambiguator, Session}; use std::fs as std_fs; use std::io; @@ -152,7 +152,7 @@ pub fn lock_file_path(session_dir: &Path) -> PathBuf { let directory_name = session_dir.file_name().unwrap().to_string_lossy(); assert_no_characters_lost(&directory_name); - let dash_indices: Vec<_> = directory_name.match_indices("-").map(|(idx, _)| idx).collect(); + let dash_indices: Vec<_> = directory_name.match_indices('-').map(|(idx, _)| idx).collect(); if dash_indices.len() != 3 { bug!( "Encountered incremental compilation session directory with \ @@ -342,7 +342,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) { // Keep the 's-{timestamp}-{random-number}' prefix, but replace the // '-working' part with the SVH of the crate - let dash_indices: Vec<_> = old_sub_dir_name.match_indices("-").map(|(idx, _)| idx).collect(); + let dash_indices: Vec<_> = old_sub_dir_name.match_indices('-').map(|(idx, _)| idx).collect(); if dash_indices.len() != 3 { bug!( "Encountered incremental compilation session directory with \ @@ -594,7 +594,7 @@ fn extract_timestamp_from_session_dir(directory_name: &str) -> Result = directory_name.match_indices("-").map(|(idx, _)| idx).collect(); + let dash_indices: Vec<_> = directory_name.match_indices('-').map(|(idx, _)| idx).collect(); if dash_indices.len() != 3 { return Err(()); } diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 6c57f79e1a7..8a11586250d 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -1,12 +1,12 @@ //! Code to save/load the dep-graph from files. use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; -use rustc::session::Session; use rustc::ty::query::OnDiskCache; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; use rustc_serialize::opaque::Decoder; use rustc_serialize::Decodable as RustcDecodable; +use rustc_session::Session; use std::path::Path; use super::data::*; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 87f39dedd02..b465a11c99c 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -1,10 +1,10 @@ use rustc::dep_graph::{DepGraph, DepKind, WorkProduct, WorkProductId}; -use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::join; use rustc_serialize::opaque::Encoder; use rustc_serialize::Encodable as RustcEncodable; +use rustc_session::Session; use std::fs; use std::path::PathBuf; diff --git a/src/librustc_incremental/persist/work_product.rs b/src/librustc_incremental/persist/work_product.rs index 65a742a202d..aa3588b284b 100644 --- a/src/librustc_incremental/persist/work_product.rs +++ b/src/librustc_incremental/persist/work_product.rs @@ -2,8 +2,8 @@ use crate::persist::fs::*; use rustc::dep_graph::{WorkProduct, WorkProductFileKind, WorkProductId}; -use rustc::session::Session; use rustc_fs_util::link_or_copy; +use rustc_session::Session; use std::fs as std_fs; use std::path::PathBuf; @@ -13,9 +13,7 @@ pub fn copy_cgu_workproducts_to_incr_comp_cache_dir( files: &[(WorkProductFileKind, PathBuf)], ) -> Option<(WorkProductId, WorkProduct)> { debug!("copy_cgu_workproducts_to_incr_comp_cache_dir({:?},{:?})", cgu_name, files); - if sess.opts.incremental.is_none() { - return None; - } + sess.opts.incremental.as_ref()?; let saved_files = files .iter() diff --git a/src/librustc_index/lib.rs b/src/librustc_index/lib.rs index 86dd1a29d0c..e8aa1a209e9 100644 --- a/src/librustc_index/lib.rs +++ b/src/librustc_index/lib.rs @@ -1,4 +1,7 @@ #![feature(allow_internal_unstable)] +#![feature(const_if_match)] +#![feature(const_fn)] +#![feature(const_panic)] #![feature(unboxed_closures)] #![feature(test)] #![feature(fn_traits)] diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs index 1dfe97238a3..d8c67f6210c 100644 --- a/src/librustc_index/vec.rs +++ b/src/librustc_index/vec.rs @@ -120,10 +120,10 @@ macro_rules! newtype_index { impl $type { $v const MAX_AS_U32: u32 = $max; - $v const MAX: Self = Self::from_u32_const($max); + $v const MAX: Self = Self::from_u32($max); #[inline] - $v fn from_usize(value: usize) -> Self { + $v const fn from_usize(value: usize) -> Self { assert!(value <= ($max as usize)); unsafe { Self::from_u32_unchecked(value as u32) @@ -131,31 +131,13 @@ macro_rules! newtype_index { } #[inline] - $v fn from_u32(value: u32) -> Self { + $v const fn from_u32(value: u32) -> Self { assert!(value <= $max); unsafe { Self::from_u32_unchecked(value) } } - /// Hacky variant of `from_u32` for use in constants. - /// This version checks the "max" constraint by using an - /// invalid array dereference. - #[inline] - $v const fn from_u32_const(value: u32) -> Self { - // This will fail at const eval time unless `value <= - // max` is true (in which case we get the index 0). - // It will also fail at runtime, of course, but in a - // kind of wacky way. - let _ = ["out of range value used"][ - !(value <= $max) as usize - ]; - - unsafe { - Self { private: value } - } - } - #[inline] $v const unsafe fn from_u32_unchecked(value: u32) -> Self { Self { private: value } @@ -163,19 +145,19 @@ macro_rules! newtype_index { /// Extracts the value of this index as an integer. #[inline] - $v fn index(self) -> usize { + $v const fn index(self) -> usize { self.as_usize() } /// Extracts the value of this index as a `u32`. #[inline] - $v fn as_u32(self) -> u32 { + $v const fn as_u32(self) -> u32 { self.private } /// Extracts the value of this index as a `usize`. #[inline] - $v fn as_usize(self) -> usize { + $v const fn as_usize(self) -> usize { self.as_u32() as usize } } @@ -196,7 +178,7 @@ macro_rules! newtype_index { #[inline] fn index(self) -> usize { - usize::from(self) + self.as_usize() } } @@ -500,7 +482,7 @@ macro_rules! newtype_index { const $name:ident = $constant:expr, $($tokens:tt)*) => ( $(#[doc = $doc])* - $v const $name: $type = $type::from_u32_const($constant); + $v const $name: $type = $type::from_u32($constant); $crate::newtype_index!( @derives [$($derives,)*] @attrs [$(#[$attrs])*] diff --git a/src/librustc_infer/Cargo.toml b/src/librustc_infer/Cargo.toml new file mode 100644 index 00000000000..9ecd056430c --- /dev/null +++ b/src/librustc_infer/Cargo.toml @@ -0,0 +1,25 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_infer" +version = "0.0.0" +edition = "2018" + +[lib] +name = "rustc_infer" +path = "lib.rs" +doctest = false + +[dependencies] +graphviz = { path = "../libgraphviz" } +log = { version = "0.4", features = ["release_max_level_info", "std"] } +rustc = { path = "../librustc" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_errors = { path = "../librustc_errors" } +rustc_hir = { path = "../librustc_hir" } +rustc_index = { path = "../librustc_index" } +rustc_macros = { path = "../librustc_macros" } +rustc_session = { path = "../librustc_session" } +rustc_span = { path = "../librustc_span" } +rustc_target = { path = "../librustc_target" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc/infer/at.rs b/src/librustc_infer/infer/at.rs similarity index 98% rename from src/librustc/infer/at.rs rename to src/librustc_infer/infer/at.rs index c58f1bd87bd..04f5b03c0e1 100644 --- a/src/librustc/infer/at.rs +++ b/src/librustc_infer/infer/at.rs @@ -27,8 +27,8 @@ use super::*; -use crate::ty::relate::{Relate, TypeRelation}; -use crate::ty::Const; +use rustc::ty::relate::{Relate, TypeRelation}; +use rustc::ty::Const; pub struct At<'a, 'tcx> { pub infcx: &'a InferCtxt<'a, 'tcx>, @@ -179,7 +179,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { T: ToTrace<'tcx>, { let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b); - Trace { at: self, trace: trace, a_is_expected } + Trace { at: self, trace, a_is_expected } } } diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc_infer/infer/canonical/canonicalizer.rs similarity index 95% rename from src/librustc/infer/canonical/canonicalizer.rs rename to src/librustc_infer/infer/canonical/canonicalizer.rs index 85fafa34915..964e378f7ab 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc_infer/infer/canonical/canonicalizer.rs @@ -1,19 +1,19 @@ //! This module contains the "canonicalizer" itself. //! //! For an overview of what canonicalization is and how it fits into -//! rustc, check out the [chapter in the rustc guide][c]. +//! rustc, check out the [chapter in the rustc dev guide][c]. //! -//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html +//! [c]: https://rustc-dev-guide.rust-lang.org/traits/canonicalization.html use crate::infer::canonical::{ Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Canonicalized, OriginalQueryValues, }; use crate::infer::InferCtxt; -use crate::ty::flags::FlagComputation; -use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::subst::GenericArg; -use crate::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags}; +use rustc::ty::flags::FlagComputation; +use rustc::ty::fold::{TypeFoldable, TypeFolder}; +use rustc::ty::subst::GenericArg; +use rustc::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags}; use std::sync::atomic::Ordering; use rustc_data_structures::fx::FxHashMap; @@ -33,9 +33,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// with a mapping M that maps `'?0` to `'static`. /// /// To get a good understanding of what is happening here, check - /// out the [chapter in the rustc guide][c]. + /// out the [chapter in the rustc dev guide][c]. /// - /// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html#canonicalizing-the-query + /// [c]: https://rustc-dev-guide.rust-lang.org/traits/canonicalization.html#canonicalizing-the-query pub fn canonicalize_query( &self, value: &V, @@ -77,9 +77,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// reference to `'static` alone. /// /// To get a good understanding of what is happening here, check - /// out the [chapter in the rustc guide][c]. + /// out the [chapter in the rustc dev guide][c]. /// - /// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html#canonicalizing-the-query-result + /// [c]: https://rustc-dev-guide.rust-lang.org/traits/canonicalization.html#canonicalizing-the-query-result pub fn canonicalize_response(&self, value: &V) -> Canonicalized<'tcx, V> where V: TypeFoldable<'tcx>, @@ -357,10 +357,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { // `TyVar(vid)` is unresolved, track its universe index in the canonicalized // result. Err(mut ui) => { - if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk { - // FIXME: perf problem described in #55921. - ui = ty::UniverseIndex::ROOT; - } + // FIXME: perf problem described in #55921. + ui = ty::UniverseIndex::ROOT; self.canonicalize_ty_var( CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), @@ -447,10 +445,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { // `ConstVar(vid)` is unresolved, track its universe index in the // canonicalized result Err(mut ui) => { - if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk { - // FIXME: perf problem described in #55921. - ui = ty::UniverseIndex::ROOT; - } + // FIXME: perf problem described in #55921. + ui = ty::UniverseIndex::ROOT; return self.canonicalize_const_var( CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) }, ct, @@ -669,7 +665,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { } else { let var = self.canonical_var(info, const_var.into()); self.tcx().mk_const(ty::Const { - val: ty::ConstKind::Bound(self.binder_index, var.into()), + val: ty::ConstKind::Bound(self.binder_index, var), ty: self.fold_ty(const_var.ty), }) } diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc_infer/infer/canonical/mod.rs similarity index 97% rename from src/librustc/infer/canonical/mod.rs rename to src/librustc_infer/infer/canonical/mod.rs index f157d805bcd..0e9593e8ea6 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc_infer/infer/canonical/mod.rs @@ -17,9 +17,9 @@ //! `instantiate_query_result` method. //! //! For a more detailed look at what is happening here, check -//! out the [chapter in the rustc guide][c]. +//! out the [chapter in the rustc dev guide][c]. //! -//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html +//! [c]: https://rustc-dev-guide.rust-lang.org/traits/canonicalization.html use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind}; use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind}; @@ -29,12 +29,11 @@ use rustc::ty::{self, BoundVar, List}; use rustc_index::vec::IndexVec; use rustc_span::source_map::Span; -pub use rustc::infer::types::canonical::*; +pub use rustc::infer::canonical::*; +use substitute::CanonicalExt; mod canonicalizer; - pub mod query_response; - mod substitute; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs similarity index 88% rename from src/librustc/infer/canonical/query_response.rs rename to src/librustc_infer/infer/canonical/query_response.rs index 012900f8af5..9322df48235 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -3,74 +3,31 @@ //! encode them therein. //! //! For an overview of what canonicaliation is and how it fits into -//! rustc, check out the [chapter in the rustc guide][c]. +//! rustc, check out the [chapter in the rustc dev guide][c]. //! -//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html +//! [c]: https://rustc-dev-guide.rust-lang.org/traits/canonicalization.html -use crate::arena::ArenaAllocatable; -use crate::infer::canonical::substitute::substitute_value; +use crate::infer::canonical::substitute::{substitute_value, CanonicalExt}; use crate::infer::canonical::{ Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues, QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse, }; +use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::InferCtxtBuilder; -use crate::infer::{InferCtxt, InferOk, InferResult}; +use crate::infer::{InferCtxt, InferOk, InferResult, NLLRegionVariableOrigin}; use crate::traits::query::{Fallible, NoSolution}; -use crate::traits::TraitEngine; +use crate::traits::{DomainGoal, TraitEngine}; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use crate::ty::fold::TypeFoldable; -use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::{self, BoundVar, Ty, TyCtxt}; +use rustc::arena::ArenaAllocatable; +use rustc::ty::fold::TypeFoldable; +use rustc::ty::relate::TypeRelation; +use rustc::ty::subst::{GenericArg, GenericArgKind}; +use rustc::ty::{self, BoundVar, Ty, TyCtxt}; use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; -use rustc_span::DUMMY_SP; use std::fmt::Debug; -impl<'tcx> InferCtxtBuilder<'tcx> { - /// The "main method" for a canonicalized trait query. Given the - /// canonical key `canonical_key`, this method will create a new - /// inference context, instantiate the key, and run your operation - /// `op`. The operation should yield up a result (of type `R`) as - /// well as a set of trait obligations that must be fully - /// satisfied. These obligations will be processed and the - /// canonical result created. - /// - /// Returns `NoSolution` in the event of any error. - /// - /// (It might be mildly nicer to implement this on `TyCtxt`, and - /// not `InferCtxtBuilder`, but that is a bit tricky right now. - /// In part because we would need a `for<'tcx>` sort of - /// bound for the closure and in part because it is convenient to - /// have `'tcx` be free on this function so that we can talk about - /// `K: TypeFoldable<'tcx>`.) - pub fn enter_canonical_trait_query( - &mut self, - canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible, - ) -> Fallible> - where - K: TypeFoldable<'tcx>, - R: Debug + TypeFoldable<'tcx>, - Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable, - { - self.enter_with_canonical( - DUMMY_SP, - canonical_key, - |ref infcx, key, canonical_inference_vars| { - let mut fulfill_cx = TraitEngine::new(infcx.tcx); - let value = operation(infcx, &mut *fulfill_cx, key)?; - infcx.make_canonicalized_query_response( - canonical_inference_vars, - value, - &mut *fulfill_cx, - ) - }, - ) - } -} - impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// This method is meant to be invoked as the final step of a canonical query /// implementation. It is given: @@ -195,9 +152,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// the query before applying this function.) /// /// To get a good understanding of what is happening here, check - /// out the [chapter in the rustc guide][c]. + /// out the [chapter in the rustc dev guide][c]. /// - /// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html#processing-the-canonicalized-query-result + /// [c]: https://rustc-dev-guide.rust-lang.org/traits/canonicalization.html#processing-the-canonicalized-query-result pub fn instantiate_query_response_and_region_obligations( &self, cause: &ObligationCause<'tcx>, @@ -304,13 +261,31 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { } (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { - let ok = self.at(cause, param_env).eq(v1, v2)?; - obligations.extend(ok.into_obligations()); + TypeRelating::new( + self, + QueryTypeRelatingDelegate { + infcx: self, + param_env, + cause, + obligations: &mut obligations, + }, + ty::Variance::Invariant, + ) + .relate(&v1, &v2)?; } (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { - let ok = self.at(cause, param_env).eq(v1, v2)?; - obligations.extend(ok.into_obligations()); + TypeRelating::new( + self, + QueryTypeRelatingDelegate { + infcx: self, + param_env, + cause, + obligations: &mut obligations, + }, + ty::Variance::Invariant, + ) + .relate(&v1, &v2)?; } _ => { @@ -421,7 +396,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { for _ in num_universes_in_query..num_universes_in_response { universe_map.push(self.create_next_universe()); } - assert!(universe_map.len() >= 1); // always have the root universe + assert!(!universe_map.is_empty()); // always have the root universe assert_eq!(universe_map[ty::UniverseIndex::ROOT.as_usize()], ty::UniverseIndex::ROOT); // Every canonical query result includes values for each of @@ -630,7 +605,7 @@ pub fn make_query_region_constraints<'tcx>( assert!(givens.is_empty()); let outlives: Vec<_> = constraints - .into_iter() + .iter() .map(|(k, _)| match *k { // Swap regions because we are going from sub (<=) to outlives // (>=). @@ -656,3 +631,55 @@ pub fn make_query_region_constraints<'tcx>( QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() } } + +struct QueryTypeRelatingDelegate<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, + obligations: &'a mut Vec>, + param_env: ty::ParamEnv<'tcx>, + cause: &'a ObligationCause<'tcx>, +} + +impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { + fn create_next_universe(&mut self) -> ty::UniverseIndex { + self.infcx.create_next_universe() + } + + fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { + let origin = NLLRegionVariableOrigin::Existential { from_forall }; + self.infcx.next_nll_region_var(origin) + } + + fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { + self.infcx.tcx.mk_region(ty::RePlaceholder(placeholder)) + } + + fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { + self.infcx.next_nll_region_var_in_universe( + NLLRegionVariableOrigin::Existential { from_forall: false }, + universe, + ) + } + + fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { + self.obligations.push(Obligation { + cause: self.cause.clone(), + param_env: self.param_env, + predicate: ty::Predicate::RegionOutlives(ty::Binder::dummy(ty::OutlivesPredicate( + sup, sub, + ))), + recursion_depth: 0, + }); + } + + fn push_domain_goal(&mut self, _: DomainGoal<'tcx>) { + bug!("should never be invoked with eager normalization") + } + + fn normalization() -> NormalizationStrategy { + NormalizationStrategy::Eager + } + + fn forbid_inference_vars() -> bool { + true + } +} diff --git a/src/librustc/infer/canonical/substitute.rs b/src/librustc_infer/infer/canonical/substitute.rs similarity index 74% rename from src/librustc/infer/canonical/substitute.rs rename to src/librustc_infer/infer/canonical/substitute.rs index 92516345633..afef32c1ffe 100644 --- a/src/librustc/infer/canonical/substitute.rs +++ b/src/librustc_infer/infer/canonical/substitute.rs @@ -2,24 +2,21 @@ //! `Canonical<'tcx, T>`. //! //! For an overview of what canonicalization is and how it fits into -//! rustc, check out the [chapter in the rustc guide][c]. +//! rustc, check out the [chapter in the rustc dev guide][c]. //! -//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html +//! [c]: https://rustc-dev-guide.rust-lang.org/traits/canonicalization.html use crate::infer::canonical::{Canonical, CanonicalVarValues}; -use crate::ty::fold::TypeFoldable; -use crate::ty::subst::GenericArgKind; -use crate::ty::{self, TyCtxt}; +use rustc::ty::fold::TypeFoldable; +use rustc::ty::subst::GenericArgKind; +use rustc::ty::{self, TyCtxt}; -impl<'tcx, V> Canonical<'tcx, V> { +pub(super) trait CanonicalExt<'tcx, V> { /// Instantiate the wrapped value, replacing each canonical value /// with the value given in `var_values`. - pub fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V + fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V where - V: TypeFoldable<'tcx>, - { - self.substitute_projected(tcx, var_values, |value| value) - } + V: TypeFoldable<'tcx>; /// Allows one to apply a substitute to some subset of /// `self.value`. Invoke `projection_fn` with `self.value` to get @@ -27,7 +24,25 @@ impl<'tcx, V> Canonical<'tcx, V> { /// variables bound in `self` (usually this extracts from subset /// of `self`). Apply the substitution `var_values` to this value /// V, replacing each of the canonical variables. - pub fn substitute_projected( + fn substitute_projected( + &self, + tcx: TyCtxt<'tcx>, + var_values: &CanonicalVarValues<'tcx>, + projection_fn: impl FnOnce(&V) -> &T, + ) -> T + where + T: TypeFoldable<'tcx>; +} + +impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { + fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V + where + V: TypeFoldable<'tcx>, + { + self.substitute_projected(tcx, var_values, |value| value) + } + + fn substitute_projected( &self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, diff --git a/src/librustc/infer/combine.rs b/src/librustc_infer/infer/combine.rs similarity index 99% rename from src/librustc/infer/combine.rs rename to src/librustc_infer/infer/combine.rs index 9eb961255c2..9d06e26d9bb 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -33,15 +33,15 @@ use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use super::{InferCtxt, MiscVariable, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; -use crate::ty::error::TypeError; -use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, InferConst, Ty, TyCtxt}; -use crate::ty::{IntType, UintType}; +use rustc::ty::error::TypeError; +use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use rustc::ty::subst::SubstsRef; +use rustc::ty::{self, InferConst, Ty, TyCtxt}; +use rustc::ty::{IntType, UintType}; +use rustc_ast::ast; use rustc_hir::def_id::DefId; use rustc_span::{Span, DUMMY_SP}; -use syntax::ast; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { diff --git a/src/librustc/infer/equate.rs b/src/librustc_infer/infer/equate.rs similarity index 94% rename from src/librustc/infer/equate.rs rename to src/librustc_infer/infer/equate.rs index 018bbe03543..bb0c124a189 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc_infer/infer/equate.rs @@ -1,10 +1,10 @@ use super::combine::{CombineFields, RelationDir}; use super::Subtype; -use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::subst::SubstsRef; -use crate::ty::TyVar; -use crate::ty::{self, Ty, TyCtxt}; +use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use rustc::ty::subst::SubstsRef; +use rustc::ty::TyVar; +use rustc::ty::{self, Ty, TyCtxt}; use rustc_hir::def_id::DefId; @@ -19,7 +19,7 @@ impl<'combine, 'infcx, 'tcx> Equate<'combine, 'infcx, 'tcx> { fields: &'combine mut CombineFields<'infcx, 'tcx>, a_is_expected: bool, ) -> Equate<'combine, 'infcx, 'tcx> { - Equate { fields: fields, a_is_expected: a_is_expected } + Equate { fields, a_is_expected } } } diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs similarity index 94% rename from src/librustc/infer/error_reporting/mod.rs rename to src/librustc_infer/infer/error_reporting/mod.rs index 01390f2c719..ebbfcb28db2 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -49,17 +49,16 @@ use super::lexical_region_resolve::RegionResolutionError; use super::region_constraints::GenericKind; use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; -use crate::hir::map; -use crate::infer::opaque_types; -use crate::infer::{self, SuppressRegionErrors}; -use crate::middle::region; +use crate::infer; use crate::traits::error_reporting::report_object_safety_error; -use crate::traits::object_safety_violations; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, }; -use crate::ty::error::TypeError; -use crate::ty::{ + +use rustc::hir::map; +use rustc::middle::region; +use rustc::ty::error::TypeError; +use rustc::ty::{ self, subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TypeFoldable, @@ -143,7 +142,7 @@ pub(super) fn note_and_explain_region( // uh oh, hope no user ever sees THIS ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None), - ty::RePlaceholder(_) => (format!("any other region"), None), + ty::RePlaceholder(_) => ("any other region".to_string(), None), // FIXME(#13998) RePlaceholder should probably print like // ReFree rather than dumping Debug output on the user. @@ -194,7 +193,7 @@ fn msg_span_from_early_bound_and_free_regions( tcx: TyCtxt<'tcx>, region: ty::Region<'tcx>, ) -> (String, Option) { - let cm = tcx.sess.source_map(); + let sm = tcx.sess.source_map(); let scope = region.free_region_binding_scope(tcx); let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID); @@ -207,7 +206,7 @@ fn msg_span_from_early_bound_and_free_regions( }; let (prefix, span) = match *region { ty::ReEarlyBound(ref br) => { - let mut sp = cm.def_span(tcx.hir().span(node)); + let mut sp = sm.def_span(tcx.hir().span(node)); if let Some(param) = tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) { @@ -216,7 +215,7 @@ fn msg_span_from_early_bound_and_free_regions( (format!("the lifetime `{}` as defined on", br.name), sp) } ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(_, name), .. }) => { - let mut sp = cm.def_span(tcx.hir().span(node)); + let mut sp = sm.def_span(tcx.hir().span(node)); if let Some(param) = tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) { @@ -230,7 +229,7 @@ fn msg_span_from_early_bound_and_free_regions( } _ => ( format!("the lifetime `{}` as defined on", region), - cm.def_span(tcx.hir().span(node)), + sm.def_span(tcx.hir().span(node)), ), }, _ => bug!(), @@ -269,14 +268,14 @@ fn item_scope_tag(item: &hir::Item<'_>) -> &'static str { fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str { match item.kind { - hir::TraitItemKind::Method(..) => "method body", + hir::TraitItemKind::Fn(..) => "method body", hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item", } } fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str { match item.kind { - hir::ImplItemKind::Method(..) => "method body", + hir::ImplItemKind::Fn(..) => "method body", hir::ImplItemKind::Const(..) | hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(..) => "associated item", @@ -288,22 +287,93 @@ fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span)) } +pub fn unexpected_hidden_region_diagnostic( + tcx: TyCtxt<'tcx>, + region_scope_tree: Option<®ion::ScopeTree>, + span: Span, + hidden_ty: Ty<'tcx>, + hidden_region: ty::Region<'tcx>, +) -> DiagnosticBuilder<'tcx> { + let mut err = struct_span_err!( + tcx.sess, + span, + E0700, + "hidden type for `impl Trait` captures lifetime that does not appear in bounds", + ); + + // Explain the region we are capturing. + if let ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) = hidden_region { + // Assuming regionck succeeded (*), we ought to always be + // capturing *some* region from the fn header, and hence it + // ought to be free. So under normal circumstances, we will go + // down this path which gives a decent human readable + // explanation. + // + // (*) if not, the `tainted_by_errors` flag would be set to + // true in any case, so we wouldn't be here at all. + note_and_explain_free_region( + tcx, + &mut err, + &format!("hidden type `{}` captures ", hidden_ty), + hidden_region, + "", + ); + } else { + // Ugh. This is a painful case: the hidden region is not one + // that we can easily summarize or explain. This can happen + // in a case like + // `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`: + // + // ``` + // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> { + // if condition() { a } else { b } + // } + // ``` + // + // Here the captured lifetime is the intersection of `'a` and + // `'b`, which we can't quite express. + + if let Some(region_scope_tree) = region_scope_tree { + // If the `region_scope_tree` is available, this is being + // invoked from the "region inferencer error". We can at + // least report a really cryptic error for now. + note_and_explain_region( + tcx, + region_scope_tree, + &mut err, + &format!("hidden type `{}` captures ", hidden_ty), + hidden_region, + "", + ); + } else { + // If the `region_scope_tree` is *unavailable*, this is + // being invoked by the code that comes *after* region + // inferencing. This is a bug, as the region inferencer + // ought to have noticed the failed constraint and invoked + // error reporting, which in turn should have prevented us + // from getting trying to infer the hidden type + // completely. + tcx.sess.delay_span_bug( + span, + &format!( + "hidden type captures unexpected lifetime `{:?}` \ + but no region inference failure", + hidden_region, + ), + ); + } + } + + err +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_region_errors( &self, region_scope_tree: ®ion::ScopeTree, errors: &Vec>, - suppress: SuppressRegionErrors, ) { - debug!( - "report_region_errors(): {} errors to start, suppress = {:?}", - errors.len(), - suppress - ); - - if suppress.suppressed() { - return; - } + debug!("report_region_errors(): {} errors to start", errors.len()); // try to pre-process the errors, which will group some of them // together into a `ProcessedErrors` group: @@ -405,17 +475,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } RegionResolutionError::MemberConstraintFailure { - opaque_type_def_id, hidden_ty, member_region, - span: _, - choice_regions: _, + span, } => { let hidden_ty = self.resolve_vars_if_possible(&hidden_ty); - opaque_types::unexpected_hidden_region_diagnostic( + unexpected_hidden_region_diagnostic( self.tcx, Some(region_scope_tree), - opaque_type_def_id, + span, hidden_ty, member_region, ) @@ -747,7 +815,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .join(", "); if !lifetimes.is_empty() { if sub.regions().count() < len { - value.push_normal(lifetimes + &", "); + value.push_normal(lifetimes + ", "); } else { value.push_normal(lifetimes); } @@ -1619,7 +1687,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let failure_code = trace.cause.as_failure_code(terr); let mut diag = match failure_code { FailureCode::Error0038(did) => { - let violations = object_safety_violations(self.tcx, did); + let violations = self.tcx.object_safety_violations(did); report_object_safety_error(self.tcx, span, did, violations) } FailureCode::Error0317(failure_str) => { @@ -1782,14 +1850,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { bound_kind: GenericKind<'tcx>, sub: S, ) { - let consider = format!( - "consider adding an explicit lifetime bound {}", - if type_param_span.map(|(_, _, is_impl_trait)| is_impl_trait).unwrap_or(false) { - format!(" `{}` to `{}`...", sub, bound_kind) - } else { - format!("`{}: {}`...", bound_kind, sub) - }, - ); + let msg = "consider adding an explicit lifetime bound"; if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span { let suggestion = if is_impl_trait { format!("{} + {}", bound_kind, sub) @@ -1797,13 +1858,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let tail = if has_lifetimes { " + " } else { "" }; format!("{}: {}{}", bound_kind, sub, tail) }; - err.span_suggestion_short( + err.span_suggestion( sp, - &consider, + &format!("{}...", msg), suggestion, Applicability::MaybeIncorrect, // Issue #41966 ); } else { + let consider = format!( + "{} {}...", + msg, + if type_param_span.map(|(_, _, is_impl_trait)| is_impl_trait).unwrap_or(false) { + format!(" `{}` to `{}`", sub, bound_kind) + } else { + format!("`{}: {}`", bound_kind, sub) + }, + ); err.help(&consider); } } @@ -1819,7 +1889,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "{} may not live long enough", labeled_user_string ); - // Explicitely use the name instead of `sub`'s `Display` impl. The `Display` impl + // Explicitly use the name instead of `sub`'s `Display` impl. The `Display` impl // for the bound is not suitable for suggestions when `-Zverbose` is set because it // uses `Debug` output, so we handle it specially here so that suggestions are // always correct. @@ -2007,7 +2077,12 @@ enum FailureCode { Error0644(&'static str), } -impl<'tcx> ObligationCause<'tcx> { +trait ObligationCauseExt<'tcx> { + fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode; + fn as_requirement_str(&self) -> &'static str; +} + +impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode { use self::FailureCode::*; use crate::traits::ObligationCauseCode::*; @@ -2072,7 +2147,7 @@ impl<'tcx> ObligationCause<'tcx> { /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks /// extra information about each type, but we only care about the category. #[derive(Clone, Copy, PartialEq, Eq, Hash)] -crate enum TyCategory { +pub enum TyCategory { Closure, Opaque, Generator, diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs similarity index 96% rename from src/librustc/infer/error_reporting/need_type_info.rs rename to src/librustc_infer/infer/error_reporting/need_type_info.rs index 0d7fce7eac6..0eda4555e25 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -1,13 +1,13 @@ -use crate::hir::map::Map; use crate::infer::type_variable::TypeVariableOriginKind; use crate::infer::InferCtxt; -use crate::ty::print::Print; -use crate::ty::{self, DefIdTree, Infer, Ty, TyVar}; +use rustc::hir::map::Map; +use rustc::ty::print::Print; +use rustc::ty::{self, DefIdTree, Infer, Ty, TyVar}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FunctionRetTy, HirId, Local, Pat}; +use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::kw; use rustc_span::Span; @@ -16,7 +16,7 @@ use std::borrow::Cow; struct FindLocalByTypeVisitor<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, target_ty: Ty<'tcx>, - hir_map: &'a Map<'tcx>, + hir_map: Map<'tcx>, found_local_pattern: Option<&'tcx Pat<'tcx>>, found_arg_pattern: Option<&'tcx Pat<'tcx>>, found_ty: Option>, @@ -25,7 +25,7 @@ struct FindLocalByTypeVisitor<'a, 'tcx> { } impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> { - fn new(infcx: &'a InferCtxt<'a, 'tcx>, target_ty: Ty<'tcx>, hir_map: &'a Map<'tcx>) -> Self { + fn new(infcx: &'a InferCtxt<'a, 'tcx>, target_ty: Ty<'tcx>, hir_map: Map<'tcx>) -> Self { Self { infcx, target_ty, @@ -69,8 +69,8 @@ impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> { type Map = Map<'tcx>; - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> { - NestedVisitorMap::OnlyBodies(&self.hir_map) + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.hir_map) } fn visit_local(&mut self, local: &'tcx Local<'tcx>) { @@ -108,7 +108,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> { fn closure_return_type_suggestion( span: Span, err: &mut DiagnosticBuilder<'_>, - output: &FunctionRetTy<'_>, + output: &FnRetTy<'_>, body: &Body<'_>, descr: &str, name: &str, @@ -117,7 +117,7 @@ fn closure_return_type_suggestion( parent_descr: Option<&str>, ) { let (arrow, post) = match output { - FunctionRetTy::DefaultReturn(_) => ("-> ", " "), + FnRetTy::DefaultReturn(_) => ("-> ", " "), _ => ("", ""), }; let suggestion = match body.value.kind { @@ -223,7 +223,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(&ty); let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); - let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir()); + let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, self.tcx.hir()); let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); @@ -391,7 +391,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.span_label(pattern.span, msg); } else if let Some(e) = local_visitor.found_method_call { if let ExprKind::MethodCall(segment, ..) = &e.kind { - // Suggest specifiying type params or point out the return type of the call: + // Suggest specifying type params or point out the return type of the call: // // error[E0282]: type annotations needed // --> $DIR/type-annotations-needed-expr.rs:2:39 @@ -468,7 +468,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &segment.args, ) { let borrow = tables.borrow(); - if let Some((DefKind::Method, did)) = borrow.type_dependent_def(e.hir_id) { + if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) { let generics = self.tcx.generics_of(did); if !generics.params.is_empty() { err.span_suggestion( diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs similarity index 92% rename from src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs rename to src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs index 6a9fe19e1ac..50b324c7227 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -3,7 +3,9 @@ use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo; use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::util::common::ErrorReported; +use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::SubregionOrigin; +use rustc::util::common::ErrorReported; use rustc_errors::struct_span_err; @@ -47,6 +49,15 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { pub(super) fn try_report_anon_anon_conflict(&self) -> Option { let (span, sub, sup) = self.regions()?; + if let Some(RegionResolutionError::ConcreteFailure( + SubregionOrigin::ReferenceOutlivesReferent(..), + .., + )) = self.error + { + // This error doesn't make much sense in this case. + return None; + } + // Determine whether the sub and sup consist of both anonymous (elided) regions. let anon_reg_sup = self.tcx().is_suitable_region(sup)?; diff --git a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs similarity index 95% rename from src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs rename to src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs index 8e2592b5318..15acf632b2c 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -1,7 +1,7 @@ -use crate::hir::map::Map; use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::middle::resolve_lifetime as rl; -use crate::ty::{self, Region, TyCtxt}; +use rustc::hir::map::Map; +use rustc::middle::resolve_lifetime as rl; +use rustc::ty::{self, Region, TyCtxt}; use rustc_hir as hir; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::Node; @@ -33,11 +33,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let fndecl = match self.tcx().hir().get(hir_id) { Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. }) | Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Method(ref m, ..), + kind: hir::TraitItemKind::Fn(ref m, ..), .. }) | Node::ImplItem(&hir::ImplItem { - kind: hir::ImplItemKind::Method(ref m, ..), + kind: hir::ImplItemKind::Fn(ref m, ..), .. }) => &m.decl, _ => return None, @@ -93,8 +93,8 @@ struct FindNestedTypeVisitor<'tcx> { impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { type Map = Map<'tcx>; - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir()) + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.tcx.hir()) } fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { @@ -212,8 +212,8 @@ struct TyPathVisitor<'tcx> { impl Visitor<'tcx> for TyPathVisitor<'tcx> { type Map = Map<'tcx>; - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Map<'tcx>> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir()) + fn nested_visit_map(&mut self) -> NestedVisitorMap> { + NestedVisitorMap::OnlyBodies(self.tcx.hir()) } fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) { diff --git a/src/librustc/infer/error_reporting/nice_region_error/mod.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs similarity index 76% rename from src/librustc/infer/error_reporting/nice_region_error/mod.rs rename to src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs index b10a60ef6f1..2357ee689d5 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/mod.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs @@ -1,8 +1,8 @@ use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::lexical_region_resolve::RegionResolutionError::*; use crate::infer::InferCtxt; -use crate::ty::{self, TyCtxt}; -use crate::util::common::ErrorReported; +use rustc::ty::{self, TyCtxt}; +use rustc::util::common::ErrorReported; use rustc_errors::DiagnosticBuilder; use rustc_span::source_map::Span; @@ -17,12 +17,7 @@ mod util; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool { - if let Some(tables) = self.in_progress_tables { - let tables = tables.borrow(); - NiceRegionError::new(self, error.clone(), Some(&tables)).try_report().is_some() - } else { - NiceRegionError::new(self, error.clone(), None).try_report().is_some() - } + NiceRegionError::new(self, error.clone()).try_report().is_some() } } @@ -30,16 +25,11 @@ pub struct NiceRegionError<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, error: Option>, regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>, - tables: Option<&'cx ty::TypeckTables<'tcx>>, } impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { - pub fn new( - infcx: &'cx InferCtxt<'cx, 'tcx>, - error: RegionResolutionError<'tcx>, - tables: Option<&'cx ty::TypeckTables<'tcx>>, - ) -> Self { - Self { infcx, error: Some(error), regions: None, tables } + pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>, error: RegionResolutionError<'tcx>) -> Self { + Self { infcx, error: Some(error), regions: None } } pub fn new_from_span( @@ -47,9 +37,8 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { span: Span, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>, - tables: Option<&'cx ty::TypeckTables<'tcx>>, ) -> Self { - Self { infcx, error: None, regions: Some((span, sub, sup)), tables } + Self { infcx, error: None, regions: Some((span, sub, sup)) } } fn tcx(&self) -> TyCtxt<'tcx> { diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs similarity index 97% rename from src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs rename to src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 250dcff372c..02ce357967c 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -1,9 +1,9 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where one region is named and the other is anonymous. use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::ty; +use rustc::ty; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; -use rustc_hir::{FunctionRetTy, TyKind}; +use rustc_hir::{FnRetTy, TyKind}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// When given a `ConcreteFailure` for a function with parameters containing a named region and @@ -79,7 +79,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { { return None; } - if let FunctionRetTy::Return(ty) = &fndecl.output { + if let FnRetTy::Return(ty) = &fndecl.output { if let (TyKind::Def(_, _), ty::ReStatic) = (&ty.kind, sub) { // This is an impl Trait return that evaluates de need of 'static. // We handle this case better in `static_impl_trait`. diff --git a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs similarity index 98% rename from src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs rename to src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs index af0e5ef8005..d88e6555af9 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/outlives_closure.rs @@ -4,8 +4,8 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError::SubSupConflict; use crate::infer::SubregionOrigin; -use crate::ty::RegionKind; -use crate::util::common::ErrorReported; +use rustc::ty::RegionKind; +use rustc::util::common::ErrorReported; use rustc_hir::{Expr, ExprKind::Closure, Node}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/placeholder_error.rs similarity index 99% rename from src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs rename to src/librustc_infer/infer/error_reporting/nice_region_error/placeholder_error.rs index 0b0bd61ce77..57313dbab42 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -3,10 +3,10 @@ use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::ValuePairs; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCause, ObligationCauseCode}; -use crate::ty::error::ExpectedFound; -use crate::ty::print::{FmtPrinter, Print, RegionHighlightMode}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, TyCtxt}; +use rustc::ty::error::ExpectedFound; +use rustc::ty::print::{FmtPrinter, Print, RegionHighlightMode}; +use rustc::ty::subst::SubstsRef; +use rustc::ty::{self, TyCtxt}; use rustc_errors::DiagnosticBuilder; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; diff --git a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs similarity index 97% rename from src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs rename to src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index c6fc4cd3c15..655e28bbd3d 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -3,8 +3,8 @@ use crate::infer::error_reporting::msg_span_from_free_region; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::ty::{BoundRegion, FreeRegion, RegionKind}; -use crate::util::common::ErrorReported; +use rustc::ty::{BoundRegion, FreeRegion, RegionKind}; +use rustc::util::common::ErrorReported; use rustc_errors::Applicability; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { diff --git a/src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs similarity index 97% rename from src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs rename to src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs index a33cb511133..f8cab9f84c8 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -4,8 +4,8 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{Subtype, ValuePairs}; use crate::traits::ObligationCauseCode::CompareImplMethodObligation; -use crate::ty::Ty; -use crate::util::common::ErrorReported; +use rustc::ty::Ty; +use rustc::util::common::ErrorReported; use rustc_span::Span; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs similarity index 62% rename from src/librustc/infer/error_reporting/nice_region_error/util.rs rename to src/librustc_infer/infer/error_reporting/nice_region_error/util.rs index 52ccb1454ee..de72c276595 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/util.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs @@ -2,7 +2,7 @@ //! anonymous regions. use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::ty::{self, DefIdTree, Region, Ty}; +use rustc::ty::{self, DefIdTree, Region, Ty}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_span::Span; @@ -51,52 +51,44 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }; let hir = &self.tcx().hir(); - if let Some(hir_id) = hir.as_local_hir_id(id) { - if let Some(body_id) = hir.maybe_body_owned_by(hir_id) { - let body = hir.body(body_id); - let owner_id = hir.body_owner(body_id); - let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap(); - if let Some(tables) = self.tables { - body.params - .iter() - .enumerate() - .filter_map(|(index, param)| { - // May return None; sometimes the tables are not yet populated. - let ty_hir_id = fn_decl.inputs[index].hir_id; - let param_ty_span = hir.span(ty_hir_id); - let ty = tables.node_type_opt(param.hir_id)?; - let mut found_anon_region = false; - let new_param_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { - if *r == *anon_region { - found_anon_region = true; - replace_region - } else { - r - } - }); - if found_anon_region { - let is_first = index == 0; - Some(AnonymousParamInfo { - param: param, - param_ty: new_param_ty, - param_ty_span: param_ty_span, - bound_region: bound_region, - is_first: is_first, - }) - } else { - None - } - }) - .next() + let hir_id = hir.as_local_hir_id(id)?; + let body_id = hir.maybe_body_owned_by(hir_id)?; + let body = hir.body(body_id); + let owner_id = hir.body_owner(body_id); + let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap(); + let poly_fn_sig = self.tcx().fn_sig(id); + let fn_sig = self.tcx().liberate_late_bound_regions(id, &poly_fn_sig); + body.params + .iter() + .enumerate() + .filter_map(|(index, param)| { + // May return None; sometimes the tables are not yet populated. + let ty = fn_sig.inputs()[index]; + let mut found_anon_region = false; + let new_param_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { + if *r == *anon_region { + found_anon_region = true; + replace_region + } else { + r + } + }); + if found_anon_region { + let ty_hir_id = fn_decl.inputs[index].hir_id; + let param_ty_span = hir.span(ty_hir_id); + let is_first = index == 0; + Some(AnonymousParamInfo { + param, + param_ty: new_param_ty, + param_ty_span, + bound_region, + is_first, + }) } else { None } - } else { - None - } - } else { - None - } + }) + .next() } // Here, we check for the case where the anonymous region diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc_infer/infer/error_reporting/note.rs similarity index 99% rename from src/librustc/infer/error_reporting/note.rs rename to src/librustc_infer/infer/error_reporting/note.rs index 11dda71b8cb..5c0caa48d0e 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc_infer/infer/error_reporting/note.rs @@ -1,8 +1,8 @@ -use crate::infer::error_reporting::note_and_explain_region; +use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt}; use crate::infer::{self, InferCtxt, SubregionOrigin}; -use crate::middle::region; -use crate::ty::error::TypeError; -use crate::ty::{self, Region}; +use rustc::middle::region; +use rustc::ty::error::TypeError; +use rustc::ty::{self, Region}; use rustc_errors::{struct_span_err, DiagnosticBuilder}; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { @@ -645,8 +645,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.sess, span, E0491, - "in type `{}`, reference has a longer lifetime \ - than the data it references", + "in type `{}`, reference has a longer lifetime than the data it references", self.ty_to_string(ty) ); note_and_explain_region( diff --git a/src/librustc/infer/freshen.rs b/src/librustc_infer/infer/freshen.rs similarity index 97% rename from src/librustc/infer/freshen.rs rename to src/librustc_infer/infer/freshen.rs index 0190989267b..a454feea36b 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc_infer/infer/freshen.rs @@ -31,8 +31,8 @@ //! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type //! inferencer knows "so far". -use crate::ty::fold::TypeFolder; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::fold::TypeFolder; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashMap; @@ -143,10 +143,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() - && !t.has_erasable_regions() - && !(t.has_closure_types() && self.infcx.in_progress_tables.is_some()) - { + if !t.needs_infer() && !t.has_erasable_regions() { return t; } diff --git a/src/librustc/infer/fudge.rs b/src/librustc_infer/infer/fudge.rs similarity index 98% rename from src/librustc/infer/fudge.rs rename to src/librustc_infer/infer/fudge.rs index d0b7bb32b98..16bf0f3d1c6 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc_infer/infer/fudge.rs @@ -1,5 +1,5 @@ -use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; +use rustc::ty::fold::{TypeFoldable, TypeFolder}; +use rustc::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; use super::type_variable::TypeVariableOrigin; use super::InferCtxt; diff --git a/src/librustc/infer/glb.rs b/src/librustc_infer/infer/glb.rs similarity index 95% rename from src/librustc/infer/glb.rs rename to src/librustc_infer/infer/glb.rs index 6ef92132bc7..8b26bcef573 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc_infer/infer/glb.rs @@ -4,8 +4,8 @@ use super::InferCtxt; use super::Subtype; use crate::traits::ObligationCause; -use crate::ty::relate::{Relate, RelateResult, TypeRelation}; -use crate::ty::{self, Ty, TyCtxt}; +use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc::ty::{self, Ty, TyCtxt}; /// "Greatest lower bound" (common subtype) pub struct Glb<'combine, 'infcx, 'tcx> { @@ -18,7 +18,7 @@ impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> { fields: &'combine mut CombineFields<'infcx, 'tcx>, a_is_expected: bool, ) -> Glb<'combine, 'infcx, 'tcx> { - Glb { fields: fields, a_is_expected: a_is_expected } + Glb { fields, a_is_expected } } } diff --git a/src/librustc_infer/infer/higher_ranked/README.md b/src/librustc_infer/infer/higher_ranked/README.md new file mode 100644 index 00000000000..533d0ef7e6c --- /dev/null +++ b/src/librustc_infer/infer/higher_ranked/README.md @@ -0,0 +1,8 @@ +To learn more about how Higher-ranked trait bounds work in the _old_ trait +solver, see [this chapter][oldhrtb] of the rustc-dev-guide. + +To learn more about how they work in the _new_ trait solver, see [this +chapter][newhrtb]. + +[oldhrtb]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html +[newhrtb]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference.html#placeholders-and-universes diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc_infer/infer/higher_ranked/mod.rs similarity index 95% rename from src/librustc/infer/higher_ranked/mod.rs rename to src/librustc_infer/infer/higher_ranked/mod.rs index 1b0f399ca33..105b987f85e 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc_infer/infer/higher_ranked/mod.rs @@ -5,8 +5,8 @@ use super::combine::CombineFields; use super::{HigherRankedType, InferCtxt, PlaceholderMap}; use crate::infer::CombinedSnapshot; -use crate::ty::relate::{Relate, RelateResult, TypeRelation}; -use crate::ty::{self, Binder, TypeFoldable}; +use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc::ty::{self, Binder, TypeFoldable}; impl<'a, 'tcx> CombineFields<'a, 'tcx> { pub fn higher_ranked_sub( @@ -71,9 +71,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// needed (but is also permitted). /// /// For more information about how placeholders and HRTBs work, see - /// the [rustc guide]. + /// the [rustc dev guide]. /// - /// [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html + /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html pub fn replace_bound_vars_with_placeholders( &self, binder: &ty::Binder, diff --git a/src/librustc/infer/lattice.rs b/src/librustc_infer/infer/lattice.rs similarity index 97% rename from src/librustc/infer/lattice.rs rename to src/librustc_infer/infer/lattice.rs index df475af1151..42f9b3ab770 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc_infer/infer/lattice.rs @@ -23,9 +23,9 @@ use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::InferCtxt; use crate::traits::ObligationCause; -use crate::ty::relate::{RelateResult, TypeRelation}; -use crate::ty::TyVar; -use crate::ty::{self, Ty}; +use rustc::ty::relate::{RelateResult, TypeRelation}; +use rustc::ty::TyVar; +use rustc::ty::{self, Ty}; pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> { fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>; diff --git a/src/librustc/infer/lexical_region_resolve/README.md b/src/librustc_infer/infer/lexical_region_resolve/README.md similarity index 59% rename from src/librustc/infer/lexical_region_resolve/README.md rename to src/librustc_infer/infer/lexical_region_resolve/README.md index c26b5625a90..e0b2c0bffee 100644 --- a/src/librustc/infer/lexical_region_resolve/README.md +++ b/src/librustc_infer/infer/lexical_region_resolve/README.md @@ -2,6 +2,6 @@ Lexical Region Resolution was removed in https://github.com/rust-lang/rust/pull/64790. Rust now uses Non-lexical lifetimes. For more info, please see the [borrowck -chapter][bc] in the rustc-guide. +chapter][bc] in the rustc-dev-guide. -[bc]: https://rust-lang.github.io/rustc-guide/borrow_check/region_inference.html +[bc]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference.html diff --git a/src/librustc/infer/lexical_region_resolve/graphviz.rs b/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs similarity index 98% rename from src/librustc/infer/lexical_region_resolve/graphviz.rs rename to src/librustc_infer/infer/lexical_region_resolve/graphviz.rs index a930e707c5c..eb52f10e408 100644 --- a/src/librustc/infer/lexical_region_resolve/graphviz.rs +++ b/src/librustc_infer/infer/lexical_region_resolve/graphviz.rs @@ -11,9 +11,9 @@ use graphviz as dot; use super::Constraint; use crate::infer::region_constraints::RegionConstraintData; use crate::infer::SubregionOrigin; -use crate::middle::free_region::RegionRelations; -use crate::middle::region; -use crate::ty; +use rustc::middle::free_region::RegionRelations; +use rustc::middle::region; +use rustc::ty; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::DefIndex; diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc_infer/infer/lexical_region_resolve/mod.rs similarity index 95% rename from src/librustc/infer/lexical_region_resolve/mod.rs rename to src/librustc_infer/infer/lexical_region_resolve/mod.rs index e0a8c3b4e65..3af10e850d5 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc_infer/infer/lexical_region_resolve/mod.rs @@ -7,18 +7,18 @@ use crate::infer::region_constraints::RegionConstraintData; use crate::infer::region_constraints::VarInfos; use crate::infer::region_constraints::VerifyBound; use crate::infer::RegionVariableOrigin; +use crate::infer::RegionckMode; use crate::infer::SubregionOrigin; -use crate::middle::free_region::RegionRelations; -use crate::ty::fold::TypeFoldable; -use crate::ty::{self, Ty, TyCtxt}; -use crate::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic}; -use crate::ty::{ReLateBound, RePlaceholder, ReScope, ReVar}; -use crate::ty::{Region, RegionVid}; +use rustc::middle::free_region::RegionRelations; +use rustc::ty::fold::TypeFoldable; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic}; +use rustc::ty::{ReLateBound, RePlaceholder, ReScope, ReVar}; +use rustc::ty::{Region, RegionVid}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::implementation::{ Direction, Graph, NodeIndex, INCOMING, OUTGOING, }; -use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_span::Span; use std::fmt; @@ -34,12 +34,29 @@ pub fn resolve<'tcx>( region_rels: &RegionRelations<'_, 'tcx>, var_infos: VarInfos, data: RegionConstraintData<'tcx>, + mode: RegionckMode, ) -> (LexicalRegionResolutions<'tcx>, Vec>) { debug!("RegionConstraintData: resolve_regions()"); let mut errors = vec![]; let mut resolver = LexicalResolver { region_rels, var_infos, data }; - let values = resolver.infer_variable_values(&mut errors); - (values, errors) + match mode { + RegionckMode::Solve => { + let values = resolver.infer_variable_values(&mut errors); + (values, errors) + } + RegionckMode::Erase { suppress_errors: false } => { + // Do real inference to get errors, then erase the results. + let mut values = resolver.infer_variable_values(&mut errors); + let re_erased = region_rels.tcx.lifetimes.re_erased; + + values.values.iter_mut().for_each(|v| *v = VarValue::Value(re_erased)); + (values, errors) + } + RegionckMode::Erase { suppress_errors: true } => { + // Skip region inference entirely. + (resolver.erased_data(region_rels.tcx), Vec::new()) + } + } } /// Contains the result of lexical region resolution. Offers methods @@ -95,13 +112,7 @@ pub enum RegionResolutionError<'tcx> { /// Indicates a failure of a `MemberConstraint`. These arise during /// impl trait processing explicitly -- basically, the impl trait's hidden type /// included some region that it was not supposed to. - MemberConstraintFailure { - span: Span, - opaque_type_def_id: DefId, - hidden_ty: Ty<'tcx>, - member_region: Region<'tcx>, - choice_regions: Vec>, - }, + MemberConstraintFailure { span: Span, hidden_ty: Ty<'tcx>, member_region: Region<'tcx> }, } struct RegionAndOrigin<'tcx> { @@ -170,6 +181,19 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } + /// An erased version of the lexical region resolutions. Used when we're + /// erasing regions and suppressing errors: in item bodies with + /// `-Zborrowck=mir`. + fn erased_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> { + LexicalRegionResolutions { + error_region: tcx.lifetimes.re_static, + values: IndexVec::from_elem_n( + VarValue::Value(tcx.lifetimes.re_erased), + self.num_vars(), + ), + } + } + fn dump_constraints(&self, free_regions: &RegionRelations<'_, 'tcx>) { debug!("----() Start constraint listing (context={:?}) ()----", free_regions.context); for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() { @@ -656,10 +680,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let span = self.tcx().def_span(member_constraint.opaque_type_def_id); errors.push(RegionResolutionError::MemberConstraintFailure { span, - opaque_type_def_id: member_constraint.opaque_type_def_id, hidden_ty: member_constraint.hidden_ty, member_region, - choice_regions: choice_regions.collect(), }); } } @@ -760,7 +782,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { let dummy_source = graph.add_node(()); let dummy_sink = graph.add_node(()); - for (constraint, _) in &self.data.constraints { + for constraint in self.data.constraints.keys() { match *constraint { Constraint::VarSubVar(a_id, b_id) => { graph.add_edge( @@ -857,7 +879,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { for upper_bound in &upper_bounds { if let ty::RePlaceholder(p) = upper_bound.region { if node_universe.cannot_name(p.universe) { - let origin = self.var_infos[node_idx].origin.clone(); + let origin = self.var_infos[node_idx].origin; errors.push(RegionResolutionError::UpperBoundUniverseConflict( node_idx, origin, diff --git a/src/librustc/infer/lub.rs b/src/librustc_infer/infer/lub.rs similarity index 95% rename from src/librustc/infer/lub.rs rename to src/librustc_infer/infer/lub.rs index 6a699f803c7..20ddeec6850 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc_infer/infer/lub.rs @@ -4,8 +4,8 @@ use super::InferCtxt; use super::Subtype; use crate::traits::ObligationCause; -use crate::ty::relate::{Relate, RelateResult, TypeRelation}; -use crate::ty::{self, Ty, TyCtxt}; +use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc::ty::{self, Ty, TyCtxt}; /// "Least upper bound" (common supertype) pub struct Lub<'combine, 'infcx, 'tcx> { @@ -18,7 +18,7 @@ impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> { fields: &'combine mut CombineFields<'infcx, 'tcx>, a_is_expected: bool, ) -> Lub<'combine, 'infcx, 'tcx> { - Lub { fields: fields, a_is_expected: a_is_expected } + Lub { fields, a_is_expected } } } diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs new file mode 100644 index 00000000000..391fce946bf --- /dev/null +++ b/src/librustc_infer/infer/mod.rs @@ -0,0 +1,1790 @@ +//! See the Book for more information. + +pub use self::freshen::TypeFreshener; +pub use self::LateBoundRegionConversionTime::*; +pub use self::RegionVariableOrigin::*; +pub use self::SubregionOrigin::*; +pub use self::ValuePairs::*; + +use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; + +use rustc::infer::canonical::{Canonical, CanonicalVarValues}; +use rustc::infer::unify_key::{ConstVarValue, ConstVariableValue}; +use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; +use rustc::middle::free_region::RegionRelations; +use rustc::middle::region; +use rustc::mir; +use rustc::mir::interpret::ConstEvalResult; +use rustc::traits::select; +use rustc::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; +use rustc::ty::fold::{TypeFoldable, TypeFolder}; +use rustc::ty::relate::RelateResult; +use rustc::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; +pub use rustc::ty::IntVarValue; +use rustc::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; +use rustc::ty::{ConstVid, FloatVid, IntVid, TyVid}; +use rustc_ast::ast; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::sync::Lrc; +use rustc_data_structures::unify as ut; +use rustc_errors::DiagnosticBuilder; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_session::config::BorrowckMode; +use rustc_span::symbol::Symbol; +use rustc_span::Span; + +use std::cell::{Cell, Ref, RefCell}; +use std::collections::BTreeMap; +use std::fmt; + +use self::combine::CombineFields; +use self::lexical_region_resolve::LexicalRegionResolutions; +use self::outlives::env::OutlivesEnvironment; +use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound}; +use self::region_constraints::{RegionConstraintCollector, RegionSnapshot}; +use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; + +pub mod at; +pub mod canonical; +mod combine; +mod equate; +pub mod error_reporting; +mod freshen; +mod fudge; +mod glb; +mod higher_ranked; +pub mod lattice; +mod lexical_region_resolve; +mod lub; +pub mod nll_relate; +pub mod outlives; +pub mod region_constraints; +pub mod resolve; +mod sub; +pub mod type_variable; + +use crate::infer::canonical::OriginalQueryValues; +pub use rustc::infer::unify_key; + +#[must_use] +#[derive(Debug)] +pub struct InferOk<'tcx, T> { + pub value: T, + pub obligations: PredicateObligations<'tcx>, +} +pub type InferResult<'tcx, T> = Result, TypeError<'tcx>>; + +pub type Bound = Option; +pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" +pub type FixupResult<'tcx, T> = Result>; // "fixup result" + +/// How we should handle region solving. +/// +/// This is used so that the region values inferred by HIR region solving are +/// not exposed, and so that we can avoid doing work in HIR typeck that MIR +/// typeck will also do. +#[derive(Copy, Clone, Debug)] +pub enum RegionckMode { + /// The default mode: report region errors, don't erase regions. + Solve, + /// Erase the results of region after solving. + Erase { + /// A flag that is used to suppress region errors, when we are doing + /// region checks that the NLL borrow checker will also do -- it might + /// be set to true. + suppress_errors: bool, + }, +} + +impl Default for RegionckMode { + fn default() -> Self { + RegionckMode::Solve + } +} + +impl RegionckMode { + pub fn suppressed(self) -> bool { + match self { + Self::Solve => false, + Self::Erase { suppress_errors } => suppress_errors, + } + } + + /// Indicates that the MIR borrowck will repeat these region + /// checks, so we should ignore errors if NLL is (unconditionally) + /// enabled. + pub fn for_item_body(tcx: TyCtxt<'_>) -> Self { + // FIXME(Centril): Once we actually remove `::Migrate` also make + // this always `true` and then proceed to eliminate the dead code. + match tcx.borrowck_mode() { + // If we're on Migrate mode, report AST region errors + BorrowckMode::Migrate => RegionckMode::Erase { suppress_errors: false }, + + // If we're on MIR, don't report AST region errors as they should be reported by NLL + BorrowckMode::Mir => RegionckMode::Erase { suppress_errors: true }, + } + } +} + +/// This type contains all the things within `InferCtxt` that sit within a +/// `RefCell` and are involved with taking/rolling back snapshots. Snapshot +/// operations are hot enough that we want only one call to `borrow_mut` per +/// call to `start_snapshot` and `rollback_to`. +pub struct InferCtxtInner<'tcx> { + /// Cache for projections. This cache is snapshotted along with the infcx. + /// + /// Public so that `traits::project` can use it. + pub projection_cache: traits::ProjectionCache<'tcx>, + + /// We instantiate `UnificationTable` with `bounds` because the types + /// that might instantiate a general type variable have an order, + /// represented by its upper and lower bounds. + type_variables: type_variable::TypeVariableTable<'tcx>, + + /// Map from const parameter variable to the kind of const it represents. + const_unification_table: ut::UnificationTable>>, + + /// Map from integral variable to the kind of integer it represents. + int_unification_table: ut::UnificationTable>, + + /// Map from floating variable to the kind of float it represents. + float_unification_table: ut::UnificationTable>, + + /// Tracks the set of region variables and the constraints between them. + /// This is initially `Some(_)` but when + /// `resolve_regions_and_report_errors` is invoked, this gets set to `None` + /// -- further attempts to perform unification, etc., may fail if new + /// region constraints would've been added. + region_constraints: Option>, + + /// A set of constraints that regionck must validate. Each + /// constraint has the form `T:'a`, meaning "some type `T` must + /// outlive the lifetime 'a". These constraints derive from + /// instantiated type parameters. So if you had a struct defined + /// like + /// + /// struct Foo { ... } + /// + /// then in some expression `let x = Foo { ... }` it will + /// instantiate the type parameter `T` with a fresh type `$0`. At + /// the same time, it will record a region obligation of + /// `$0:'static`. This will get checked later by regionck. (We + /// can't generally check these things right away because we have + /// to wait until types are resolved.) + /// + /// These are stored in a map keyed to the id of the innermost + /// enclosing fn body / static initializer expression. This is + /// because the location where the obligation was incurred can be + /// relevant with respect to which sublifetime assumptions are in + /// place. The reason that we store under the fn-id, and not + /// something more fine-grained, is so that it is easier for + /// regionck to be sure that it has found *all* the region + /// obligations (otherwise, it's easy to fail to walk to a + /// particular node-id). + /// + /// Before running `resolve_regions_and_report_errors`, the creator + /// of the inference context is expected to invoke + /// `process_region_obligations` (defined in `self::region_obligations`) + /// for each body-id in this map, which will process the + /// obligations within. This is expected to be done 'late enough' + /// that all type inference variables have been bound and so forth. + pub region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>, +} + +impl<'tcx> InferCtxtInner<'tcx> { + fn new() -> InferCtxtInner<'tcx> { + InferCtxtInner { + projection_cache: Default::default(), + type_variables: type_variable::TypeVariableTable::new(), + const_unification_table: ut::UnificationTable::new(), + int_unification_table: ut::UnificationTable::new(), + float_unification_table: ut::UnificationTable::new(), + region_constraints: Some(RegionConstraintCollector::new()), + region_obligations: vec![], + } + } + + pub fn unwrap_region_constraints(&mut self) -> &mut RegionConstraintCollector<'tcx> { + self.region_constraints.as_mut().expect("region constraints already solved") + } +} + +pub struct InferCtxt<'a, 'tcx> { + pub tcx: TyCtxt<'tcx>, + + /// During type-checking/inference of a body, `in_progress_tables` + /// contains a reference to the tables being built up, which are + /// used for reading closure kinds/signatures as they are inferred, + /// and for error reporting logic to read arbitrary node types. + pub in_progress_tables: Option<&'a RefCell>>, + + pub inner: RefCell>, + + /// If set, this flag causes us to skip the 'leak check' during + /// higher-ranked subtyping operations. This flag is a temporary one used + /// to manage the removal of the leak-check: for the time being, we still run the + /// leak-check, but we issue warnings. This flag can only be set to true + /// when entering a snapshot. + skip_leak_check: Cell, + + /// Once region inference is done, the values for each variable. + lexical_region_resolutions: RefCell>>, + + /// Caches the results of trait selection. This cache is used + /// for things that have to do with the parameters in scope. + pub selection_cache: select::SelectionCache<'tcx>, + + /// Caches the results of trait evaluation. + pub evaluation_cache: select::EvaluationCache<'tcx>, + + /// the set of predicates on which errors have been reported, to + /// avoid reporting the same error twice. + pub reported_trait_errors: RefCell>>>, + + pub reported_closure_mismatch: RefCell)>>, + + /// When an error occurs, we want to avoid reporting "derived" + /// errors that are due to this original failure. Normally, we + /// handle this with the `err_count_on_creation` count, which + /// basically just tracks how many errors were reported when we + /// started type-checking a fn and checks to see if any new errors + /// have been reported since then. Not great, but it works. + /// + /// However, when errors originated in other passes -- notably + /// resolve -- this heuristic breaks down. Therefore, we have this + /// auxiliary flag that one can set whenever one creates a + /// type-error that is due to an error in a prior pass. + /// + /// Don't read this flag directly, call `is_tainted_by_errors()` + /// and `set_tainted_by_errors()`. + tainted_by_errors_flag: Cell, + + /// Track how many errors were reported when this infcx is created. + /// If the number of errors increases, that's also a sign (line + /// `tained_by_errors`) to avoid reporting certain kinds of errors. + // FIXME(matthewjasper) Merge into `tainted_by_errors_flag` + err_count_on_creation: usize, + + /// This flag is true while there is an active snapshot. + in_snapshot: Cell, + + /// What is the innermost universe we have created? Starts out as + /// `UniverseIndex::root()` but grows from there as we enter + /// universal quantifiers. + /// + /// N.B., at present, we exclude the universal quantifiers on the + /// item we are type-checking, and just consider those names as + /// part of the root universe. So this would only get incremented + /// when we enter into a higher-ranked (`for<..>`) type or trait + /// bound. + universe: Cell, +} + +/// A map returned by `replace_bound_vars_with_placeholders()` +/// indicating the placeholder region that each late-bound region was +/// replaced with. +pub type PlaceholderMap<'tcx> = BTreeMap>; + +/// See the `error_reporting` module for more details. +#[derive(Clone, Debug, PartialEq, Eq, TypeFoldable)] +pub enum ValuePairs<'tcx> { + Types(ExpectedFound>), + Regions(ExpectedFound>), + Consts(ExpectedFound<&'tcx ty::Const<'tcx>>), + TraitRefs(ExpectedFound>), + PolyTraitRefs(ExpectedFound>), +} + +/// The trace designates the path through inference that we took to +/// encounter an error or subtyping constraint. +/// +/// See the `error_reporting` module for more details. +#[derive(Clone, Debug)] +pub struct TypeTrace<'tcx> { + cause: ObligationCause<'tcx>, + values: ValuePairs<'tcx>, +} + +/// The origin of a `r1 <= r2` constraint. +/// +/// See `error_reporting` module for more details +#[derive(Clone, Debug)] +pub enum SubregionOrigin<'tcx> { + /// Arose from a subtyping relation + Subtype(Box>), + + /// Stack-allocated closures cannot outlive innermost loop + /// or function so as to ensure we only require finite stack + InfStackClosure(Span), + + /// Invocation of closure must be within its lifetime + InvokeClosure(Span), + + /// Dereference of reference must be within its lifetime + DerefPointer(Span), + + /// Closure bound must not outlive captured variables + ClosureCapture(Span, hir::HirId), + + /// Index into slice must be within its lifetime + IndexSlice(Span), + + /// When casting `&'a T` to an `&'b Trait` object, + /// relating `'a` to `'b` + RelateObjectBound(Span), + + /// Some type parameter was instantiated with the given type, + /// and that type must outlive some region. + RelateParamBound(Span, Ty<'tcx>), + + /// The given region parameter was instantiated with a region + /// that must outlive some other region. + RelateRegionParamBound(Span), + + /// A bound placed on type parameters that states that must outlive + /// the moment of their instantiation. + RelateDefaultParamBound(Span, Ty<'tcx>), + + /// Creating a pointer `b` to contents of another reference + Reborrow(Span), + + /// Creating a pointer `b` to contents of an upvar + ReborrowUpvar(Span, ty::UpvarId), + + /// Data with type `Ty<'tcx>` was borrowed + DataBorrowed(Ty<'tcx>, Span), + + /// (&'a &'b T) where a >= b + ReferenceOutlivesReferent(Ty<'tcx>, Span), + + /// Type or region parameters must be in scope. + ParameterInScope(ParameterOrigin, Span), + + /// The type T of an expression E must outlive the lifetime for E. + ExprTypeIsNotInScope(Ty<'tcx>, Span), + + /// A `ref b` whose region does not enclose the decl site + BindingTypeIsNotValidAtDecl(Span), + + /// Regions appearing in a method receiver must outlive method call + CallRcvr(Span), + + /// Regions appearing in a function argument must outlive func call + CallArg(Span), + + /// Region in return type of invoked fn must enclose call + CallReturn(Span), + + /// Operands must be in scope + Operand(Span), + + /// Region resulting from a `&` expr must enclose the `&` expr + AddrOf(Span), + + /// An auto-borrow that does not enclose the expr where it occurs + AutoBorrow(Span), + + /// Region constraint arriving from destructor safety + SafeDestructor(Span), + + /// Comparing the signature and requirements of an impl method against + /// the containing trait. + CompareImplMethodObligation { + span: Span, + item_name: ast::Name, + impl_item_def_id: DefId, + trait_item_def_id: DefId, + }, +} + +// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert_size!(SubregionOrigin<'_>, 32); + +/// Places that type/region parameters can appear. +#[derive(Clone, Copy, Debug)] +pub enum ParameterOrigin { + Path, // foo::bar + MethodCall, // foo.bar() <-- parameters on impl providing bar() + OverloadedOperator, // a + b when overloaded + OverloadedDeref, // *a when overloaded +} + +/// Times when we replace late-bound regions with variables: +#[derive(Clone, Copy, Debug)] +pub enum LateBoundRegionConversionTime { + /// when a fn is called + FnCall, + + /// when two higher-ranked types are compared + HigherRankedType, + + /// when projecting an associated type + AssocTypeProjection(DefId), +} + +/// Reasons to create a region inference variable +/// +/// See `error_reporting` module for more details +#[derive(Copy, Clone, Debug)] +pub enum RegionVariableOrigin { + /// Region variables created for ill-categorized reasons, + /// mostly indicates places in need of refactoring + MiscVariable(Span), + + /// Regions created by a `&P` or `[...]` pattern + PatternRegion(Span), + + /// Regions created by `&` operator + AddrOfRegion(Span), + + /// Regions created as part of an autoref of a method receiver + Autoref(Span), + + /// Regions created as part of an automatic coercion + Coercion(Span), + + /// Region variables created as the values for early-bound regions + EarlyBoundRegion(Span, Symbol), + + /// Region variables created for bound regions + /// in a function or method that is called + LateBoundRegion(Span, ty::BoundRegion, LateBoundRegionConversionTime), + + UpvarRegion(ty::UpvarId, Span), + + BoundRegionInCoherence(ast::Name), + + /// This origin is used for the inference variables that we create + /// during NLL region processing. + NLL(NLLRegionVariableOrigin), +} + +#[derive(Copy, Clone, Debug)] +pub enum NLLRegionVariableOrigin { + /// During NLL region processing, we create variables for free + /// regions that we encounter in the function signature and + /// elsewhere. This origin indices we've got one of those. + FreeRegion, + + /// "Universal" instantiation of a higher-ranked region (e.g., + /// from a `for<'a> T` binder). Meant to represent "any region". + Placeholder(ty::PlaceholderRegion), + + Existential { + /// If this is true, then this variable was created to represent a lifetime + /// bound in a `for` binder. For example, it might have been created to + /// represent the lifetime `'a` in a type like `for<'a> fn(&'a u32)`. + /// Such variables are created when we are trying to figure out if there + /// is any valid instantiation of `'a` that could fit into some scenario. + /// + /// This is used to inform error reporting: in the case that we are trying to + /// determine whether there is any valid instantiation of a `'a` variable that meets + /// some constraint C, we want to blame the "source" of that `for` type, + /// rather than blaming the source of the constraint C. + from_forall: bool, + }, +} + +impl NLLRegionVariableOrigin { + pub fn is_universal(self) -> bool { + match self { + NLLRegionVariableOrigin::FreeRegion => true, + NLLRegionVariableOrigin::Placeholder(..) => true, + NLLRegionVariableOrigin::Existential { .. } => false, + } + } + + pub fn is_existential(self) -> bool { + !self.is_universal() + } +} + +#[derive(Copy, Clone, Debug)] +pub enum FixupError<'tcx> { + UnresolvedIntTy(IntVid), + UnresolvedFloatTy(FloatVid), + UnresolvedTy(TyVid), + UnresolvedConst(ConstVid<'tcx>), +} + +/// See the `region_obligations` field for more information. +#[derive(Clone)] +pub struct RegionObligation<'tcx> { + pub sub_region: ty::Region<'tcx>, + pub sup_type: Ty<'tcx>, + pub origin: SubregionOrigin<'tcx>, +} + +impl<'tcx> fmt::Display for FixupError<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use self::FixupError::*; + + match *self { + UnresolvedIntTy(_) => write!( + f, + "cannot determine the type of this integer; \ + add a suffix to specify the type explicitly" + ), + UnresolvedFloatTy(_) => write!( + f, + "cannot determine the type of this number; \ + add a suffix to specify the type explicitly" + ), + UnresolvedTy(_) => write!(f, "unconstrained type"), + UnresolvedConst(_) => write!(f, "unconstrained const value"), + } + } +} + +/// Helper type of a temporary returned by `tcx.infer_ctxt()`. +/// Necessary because we can't write the following bound: +/// `F: for<'b, 'tcx> where 'tcx FnOnce(InferCtxt<'b, 'tcx>)`. +pub struct InferCtxtBuilder<'tcx> { + global_tcx: TyCtxt<'tcx>, + fresh_tables: Option>>, +} + +pub trait TyCtxtInferExt<'tcx> { + fn infer_ctxt(self) -> InferCtxtBuilder<'tcx>; +} + +impl TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { + fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { + InferCtxtBuilder { global_tcx: self, fresh_tables: None } + } +} + +impl<'tcx> InferCtxtBuilder<'tcx> { + /// Used only by `rustc_typeck` during body type-checking/inference, + /// will initialize `in_progress_tables` with fresh `TypeckTables`. + pub fn with_fresh_in_progress_tables(mut self, table_owner: DefId) -> Self { + self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty(Some(table_owner)))); + self + } + + /// Given a canonical value `C` as a starting point, create an + /// inference context that contains each of the bound values + /// within instantiated as a fresh variable. The `f` closure is + /// invoked with the new infcx, along with the instantiated value + /// `V` and a substitution `S`. This substitution `S` maps from + /// the bound values in `C` to their instantiated values in `V` + /// (in other words, `S(C) = V`). + pub fn enter_with_canonical( + &mut self, + span: Span, + canonical: &Canonical<'tcx, T>, + f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>, T, CanonicalVarValues<'tcx>) -> R, + ) -> R + where + T: TypeFoldable<'tcx>, + { + self.enter(|infcx| { + let (value, subst) = + infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); + f(infcx, value, subst) + }) + } + + pub fn enter(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R { + let InferCtxtBuilder { global_tcx, ref fresh_tables } = *self; + let in_progress_tables = fresh_tables.as_ref(); + global_tcx.enter_local(|tcx| { + f(InferCtxt { + tcx, + in_progress_tables, + inner: RefCell::new(InferCtxtInner::new()), + lexical_region_resolutions: RefCell::new(None), + selection_cache: Default::default(), + evaluation_cache: Default::default(), + reported_trait_errors: Default::default(), + reported_closure_mismatch: Default::default(), + tainted_by_errors_flag: Cell::new(false), + err_count_on_creation: tcx.sess.err_count(), + in_snapshot: Cell::new(false), + skip_leak_check: Cell::new(false), + universe: Cell::new(ty::UniverseIndex::ROOT), + }) + }) + } +} + +impl<'tcx, T> InferOk<'tcx, T> { + pub fn unit(self) -> InferOk<'tcx, ()> { + InferOk { value: (), obligations: self.obligations } + } + + /// Extracts `value`, registering any obligations into `fulfill_cx`. + pub fn into_value_registering_obligations( + self, + infcx: &InferCtxt<'_, 'tcx>, + fulfill_cx: &mut dyn TraitEngine<'tcx>, + ) -> T { + let InferOk { value, obligations } = self; + for obligation in obligations { + fulfill_cx.register_predicate_obligation(infcx, obligation); + } + value + } +} + +impl<'tcx> InferOk<'tcx, ()> { + pub fn into_obligations(self) -> PredicateObligations<'tcx> { + self.obligations + } +} + +#[must_use = "once you start a snapshot, you should always consume it"] +pub struct CombinedSnapshot<'a, 'tcx> { + projection_cache_snapshot: traits::ProjectionCacheSnapshot, + type_snapshot: type_variable::Snapshot<'tcx>, + const_snapshot: ut::Snapshot>>, + int_snapshot: ut::Snapshot>, + float_snapshot: ut::Snapshot>, + region_constraints_snapshot: RegionSnapshot, + region_obligations_snapshot: usize, + universe: ty::UniverseIndex, + was_in_snapshot: bool, + was_skip_leak_check: bool, + _in_progress_tables: Option>>, +} + +impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + pub fn is_in_snapshot(&self) -> bool { + self.in_snapshot.get() + } + + pub fn freshen>(&self, t: T) -> T { + t.fold_with(&mut self.freshener()) + } + + pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool { + match ty.kind { + ty::Infer(ty::TyVar(vid)) => self.inner.borrow().type_variables.var_diverges(vid), + _ => false, + } + } + + pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { + freshen::TypeFreshener::new(self) + } + + pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric { + use rustc::ty::error::UnconstrainedNumeric::Neither; + use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; + match ty.kind { + ty::Infer(ty::IntVar(vid)) => { + if self.inner.borrow_mut().int_unification_table.probe_value(vid).is_some() { + Neither + } else { + UnconstrainedInt + } + } + ty::Infer(ty::FloatVar(vid)) => { + if self.inner.borrow_mut().float_unification_table.probe_value(vid).is_some() { + Neither + } else { + UnconstrainedFloat + } + } + _ => Neither, + } + } + + pub fn unsolved_variables(&self) -> Vec> { + let mut inner = self.inner.borrow_mut(); + // FIXME(const_generics): should there be an equivalent function for const variables? + + let mut vars: Vec> = inner + .type_variables + .unsolved_variables() + .into_iter() + .map(|t| self.tcx.mk_ty_var(t)) + .collect(); + vars.extend( + (0..inner.int_unification_table.len()) + .map(|i| ty::IntVid { index: i as u32 }) + .filter(|&vid| inner.int_unification_table.probe_value(vid).is_none()) + .map(|v| self.tcx.mk_int_var(v)), + ); + vars.extend( + (0..inner.float_unification_table.len()) + .map(|i| ty::FloatVid { index: i as u32 }) + .filter(|&vid| inner.float_unification_table.probe_value(vid).is_none()) + .map(|v| self.tcx.mk_float_var(v)), + ); + vars + } + + fn combine_fields( + &'a self, + trace: TypeTrace<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> CombineFields<'a, 'tcx> { + CombineFields { + infcx: self, + trace, + cause: None, + param_env, + obligations: PredicateObligations::new(), + } + } + + /// Clear the "currently in a snapshot" flag, invoke the closure, + /// then restore the flag to its original value. This flag is a + /// debugging measure designed to detect cases where we start a + /// snapshot, create type variables, and register obligations + /// which may involve those type variables in the fulfillment cx, + /// potentially leaving "dangling type variables" behind. + /// In such cases, an assertion will fail when attempting to + /// register obligations, within a snapshot. Very useful, much + /// better than grovelling through megabytes of `RUSTC_LOG` output. + /// + /// HOWEVER, in some cases the flag is unhelpful. In particular, we + /// sometimes create a "mini-fulfilment-cx" in which we enroll + /// obligations. As long as this fulfillment cx is fully drained + /// before we return, this is not a problem, as there won't be any + /// escaping obligations in the main cx. In those cases, you can + /// use this function. + pub fn save_and_restore_in_snapshot_flag(&self, func: F) -> R + where + F: FnOnce(&Self) -> R, + { + let flag = self.in_snapshot.replace(false); + let result = func(self); + self.in_snapshot.set(flag); + result + } + + fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> { + debug!("start_snapshot()"); + + let in_snapshot = self.in_snapshot.replace(true); + + let mut inner = self.inner.borrow_mut(); + CombinedSnapshot { + projection_cache_snapshot: inner.projection_cache.snapshot(), + type_snapshot: inner.type_variables.snapshot(), + const_snapshot: inner.const_unification_table.snapshot(), + int_snapshot: inner.int_unification_table.snapshot(), + float_snapshot: inner.float_unification_table.snapshot(), + region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(), + region_obligations_snapshot: inner.region_obligations.len(), + universe: self.universe(), + was_in_snapshot: in_snapshot, + was_skip_leak_check: self.skip_leak_check.get(), + // Borrow tables "in progress" (i.e., during typeck) + // to ban writes from within a snapshot to them. + _in_progress_tables: self.in_progress_tables.map(|tables| tables.borrow()), + } + } + + fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { + debug!("rollback_to(cause={})", cause); + let CombinedSnapshot { + projection_cache_snapshot, + type_snapshot, + const_snapshot, + int_snapshot, + float_snapshot, + region_constraints_snapshot, + region_obligations_snapshot, + universe, + was_in_snapshot, + was_skip_leak_check, + _in_progress_tables, + } = snapshot; + + self.in_snapshot.set(was_in_snapshot); + self.universe.set(universe); + self.skip_leak_check.set(was_skip_leak_check); + + let mut inner = self.inner.borrow_mut(); + inner.projection_cache.rollback_to(projection_cache_snapshot); + inner.type_variables.rollback_to(type_snapshot); + inner.const_unification_table.rollback_to(const_snapshot); + inner.int_unification_table.rollback_to(int_snapshot); + inner.float_unification_table.rollback_to(float_snapshot); + inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot); + inner.region_obligations.truncate(region_obligations_snapshot); + } + + fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { + debug!("commit_from()"); + let CombinedSnapshot { + projection_cache_snapshot, + type_snapshot, + const_snapshot, + int_snapshot, + float_snapshot, + region_constraints_snapshot, + region_obligations_snapshot: _, + universe: _, + was_in_snapshot, + was_skip_leak_check, + _in_progress_tables, + } = snapshot; + + self.in_snapshot.set(was_in_snapshot); + self.skip_leak_check.set(was_skip_leak_check); + + let mut inner = self.inner.borrow_mut(); + inner.projection_cache.commit(projection_cache_snapshot); + inner.type_variables.commit(type_snapshot); + inner.const_unification_table.commit(const_snapshot); + inner.int_unification_table.commit(int_snapshot); + inner.float_unification_table.commit(float_snapshot); + inner.unwrap_region_constraints().commit(region_constraints_snapshot); + } + + /// Executes `f` and commit the bindings. + pub fn commit_unconditionally(&self, f: F) -> R + where + F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, + { + debug!("commit_unconditionally()"); + let snapshot = self.start_snapshot(); + let r = f(&snapshot); + self.commit_from(snapshot); + r + } + + /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`. + pub fn commit_if_ok(&self, f: F) -> Result + where + F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result, + { + debug!("commit_if_ok()"); + let snapshot = self.start_snapshot(); + let r = f(&snapshot); + debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok()); + match r { + Ok(_) => { + self.commit_from(snapshot); + } + Err(_) => { + self.rollback_to("commit_if_ok -- error", snapshot); + } + } + r + } + + /// Execute `f` then unroll any bindings it creates. + pub fn probe(&self, f: F) -> R + where + F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, + { + debug!("probe()"); + let snapshot = self.start_snapshot(); + let r = f(&snapshot); + self.rollback_to("probe", snapshot); + r + } + + /// If `should_skip` is true, then execute `f` then unroll any bindings it creates. + pub fn probe_maybe_skip_leak_check(&self, should_skip: bool, f: F) -> R + where + F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, + { + debug!("probe()"); + let snapshot = self.start_snapshot(); + let skip_leak_check = should_skip || self.skip_leak_check.get(); + self.skip_leak_check.set(skip_leak_check); + let r = f(&snapshot); + self.rollback_to("probe", snapshot); + r + } + + /// Scan the constraints produced since `snapshot` began and returns: + /// + /// - `None` -- if none of them involve "region outlives" constraints + /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder + /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders + pub fn region_constraints_added_in_snapshot( + &self, + snapshot: &CombinedSnapshot<'a, 'tcx>, + ) -> Option { + self.inner + .borrow_mut() + .unwrap_region_constraints() + .region_constraints_added_in_snapshot(&snapshot.region_constraints_snapshot) + } + + pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) { + self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup); + } + + pub fn can_sub(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx> + where + T: at::ToTrace<'tcx>, + { + let origin = &ObligationCause::dummy(); + self.probe(|_| { + self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| { + // Ignore obligations, since we are unrolling + // everything anyway. + }) + }) + } + + pub fn can_eq(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx> + where + T: at::ToTrace<'tcx>, + { + let origin = &ObligationCause::dummy(); + self.probe(|_| { + self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| { + // Ignore obligations, since we are unrolling + // everything anyway. + }) + }) + } + + pub fn sub_regions( + &self, + origin: SubregionOrigin<'tcx>, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) { + debug!("sub_regions({:?} <: {:?})", a, b); + self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b); + } + + /// Require that the region `r` be equal to one of the regions in + /// the set `regions`. + pub fn member_constraint( + &self, + opaque_type_def_id: DefId, + definition_span: Span, + hidden_ty: Ty<'tcx>, + region: ty::Region<'tcx>, + in_regions: &Lrc>>, + ) { + debug!("member_constraint({:?} <: {:?})", region, in_regions); + self.inner.borrow_mut().unwrap_region_constraints().member_constraint( + opaque_type_def_id, + definition_span, + hidden_ty, + region, + in_regions, + ); + } + + pub fn subtype_predicate( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + predicate: &ty::PolySubtypePredicate<'tcx>, + ) -> Option> { + // Subtle: it's ok to skip the binder here and resolve because + // `shallow_resolve` just ignores anything that is not a type + // variable, and because type variable's can't (at present, at + // least) capture any of the things bound by this binder. + // + // NOTE(nmatsakis): really, there is no *particular* reason to do this + // `shallow_resolve` here except as a micro-optimization. + // Naturally I could not resist. + let two_unbound_type_vars = { + let a = self.shallow_resolve(predicate.skip_binder().a); + let b = self.shallow_resolve(predicate.skip_binder().b); + a.is_ty_var() && b.is_ty_var() + }; + + if two_unbound_type_vars { + // Two unbound type variables? Can't make progress. + return None; + } + + Some(self.commit_if_ok(|snapshot| { + let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) = + self.replace_bound_vars_with_placeholders(predicate); + + let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; + + self.leak_check(false, &placeholder_map, snapshot)?; + + Ok(ok.unit()) + })) + } + + pub fn region_outlives_predicate( + &self, + cause: &traits::ObligationCause<'tcx>, + predicate: &ty::PolyRegionOutlivesPredicate<'tcx>, + ) -> UnitResult<'tcx> { + self.commit_if_ok(|snapshot| { + let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) = + self.replace_bound_vars_with_placeholders(predicate); + let origin = SubregionOrigin::from_obligation_cause(cause, || { + RelateRegionParamBound(cause.span) + }); + self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` + self.leak_check(false, &placeholder_map, snapshot)?; + Ok(()) + }) + } + + pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid { + self.inner.borrow_mut().type_variables.new_var(self.universe(), diverging, origin) + } + + pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { + self.tcx.mk_ty_var(self.next_ty_var_id(false, origin)) + } + + pub fn next_ty_var_in_universe( + &self, + origin: TypeVariableOrigin, + universe: ty::UniverseIndex, + ) -> Ty<'tcx> { + let vid = self.inner.borrow_mut().type_variables.new_var(universe, false, origin); + self.tcx.mk_ty_var(vid) + } + + pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { + self.tcx.mk_ty_var(self.next_ty_var_id(true, origin)) + } + + pub fn next_const_var( + &self, + ty: Ty<'tcx>, + origin: ConstVariableOrigin, + ) -> &'tcx ty::Const<'tcx> { + self.tcx.mk_const_var(self.next_const_var_id(origin), ty) + } + + pub fn next_const_var_in_universe( + &self, + ty: Ty<'tcx>, + origin: ConstVariableOrigin, + universe: ty::UniverseIndex, + ) -> &'tcx ty::Const<'tcx> { + let vid = self + .inner + .borrow_mut() + .const_unification_table + .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } }); + self.tcx.mk_const_var(vid, ty) + } + + pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> { + self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue { + origin, + val: ConstVariableValue::Unknown { universe: self.universe() }, + }) + } + + fn next_int_var_id(&self) -> IntVid { + self.inner.borrow_mut().int_unification_table.new_key(None) + } + + pub fn next_int_var(&self) -> Ty<'tcx> { + self.tcx.mk_int_var(self.next_int_var_id()) + } + + fn next_float_var_id(&self) -> FloatVid { + self.inner.borrow_mut().float_unification_table.new_key(None) + } + + pub fn next_float_var(&self) -> Ty<'tcx> { + self.tcx.mk_float_var(self.next_float_var_id()) + } + + /// Creates a fresh region variable with the next available index. + /// The variable will be created in the maximum universe created + /// thus far, allowing it to name any region created thus far. + pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region<'tcx> { + self.next_region_var_in_universe(origin, self.universe()) + } + + /// Creates a fresh region variable with the next available index + /// in the given universe; typically, you can use + /// `next_region_var` and just use the maximal universe. + pub fn next_region_var_in_universe( + &self, + origin: RegionVariableOrigin, + universe: ty::UniverseIndex, + ) -> ty::Region<'tcx> { + let region_var = + self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe, origin); + self.tcx.mk_region(ty::ReVar(region_var)) + } + + /// Return the universe that the region `r` was created in. For + /// most regions (e.g., `'static`, named regions from the user, + /// etc) this is the root universe U0. For inference variables or + /// placeholders, however, it will return the universe which which + /// they are associated. + fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex { + self.inner.borrow_mut().unwrap_region_constraints().universe(r) + } + + /// Number of region variables created so far. + pub fn num_region_vars(&self) -> usize { + self.inner.borrow_mut().unwrap_region_constraints().num_region_vars() + } + + /// Just a convenient wrapper of `next_region_var` for using during NLL. + pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin) -> ty::Region<'tcx> { + self.next_region_var(RegionVariableOrigin::NLL(origin)) + } + + /// Just a convenient wrapper of `next_region_var` for using during NLL. + pub fn next_nll_region_var_in_universe( + &self, + origin: NLLRegionVariableOrigin, + universe: ty::UniverseIndex, + ) -> ty::Region<'tcx> { + self.next_region_var_in_universe(RegionVariableOrigin::NLL(origin), universe) + } + + pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> GenericArg<'tcx> { + match param.kind { + GenericParamDefKind::Lifetime => { + // Create a region inference variable for the given + // region parameter definition. + self.next_region_var(EarlyBoundRegion(span, param.name)).into() + } + GenericParamDefKind::Type { .. } => { + // Create a type inference variable for the given + // type parameter definition. The substitutions are + // for actual parameters that may be referred to by + // the default of this type parameter, if it exists. + // e.g., `struct Foo(...);` when + // used in a path such as `Foo::::new()` will + // use an inference variable for `C` with `[T, U]` + // as the substitutions for the default, `(T, U)`. + let ty_var_id = self.inner.borrow_mut().type_variables.new_var( + self.universe(), + false, + TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeParameterDefinition( + param.name, + Some(param.def_id), + ), + span, + }, + ); + + self.tcx.mk_ty_var(ty_var_id).into() + } + GenericParamDefKind::Const { .. } => { + let origin = ConstVariableOrigin { + kind: ConstVariableOriginKind::ConstParameterDefinition(param.name), + span, + }; + let const_var_id = + self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue { + origin, + val: ConstVariableValue::Unknown { universe: self.universe() }, + }); + self.tcx.mk_const_var(const_var_id, self.tcx.type_of(param.def_id)).into() + } + } + } + + /// Given a set of generics defined on a type or impl, returns a substitution mapping each + /// type/region parameter to a fresh inference variable. + pub fn fresh_substs_for_item(&self, span: Span, def_id: DefId) -> SubstsRef<'tcx> { + InternalSubsts::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param)) + } + + /// Returns `true` if errors have been reported since this infcx was + /// created. This is sometimes used as a heuristic to skip + /// reporting errors that often occur as a result of earlier + /// errors, but where it's hard to be 100% sure (e.g., unresolved + /// inference variables, regionck errors). + pub fn is_tainted_by_errors(&self) -> bool { + debug!( + "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ + tainted_by_errors_flag={})", + self.tcx.sess.err_count(), + self.err_count_on_creation, + self.tainted_by_errors_flag.get() + ); + + if self.tcx.sess.err_count() > self.err_count_on_creation { + return true; // errors reported since this infcx was made + } + self.tainted_by_errors_flag.get() + } + + /// Set the "tainted by errors" flag to true. We call this when we + /// observe an error from a prior pass. + pub fn set_tainted_by_errors(&self) { + debug!("set_tainted_by_errors()"); + self.tainted_by_errors_flag.set(true) + } + + /// Process the region constraints and report any errors that + /// result. After this, no more unification operations should be + /// done -- or the compiler will panic -- but it is legal to use + /// `resolve_vars_if_possible` as well as `fully_resolve`. + pub fn resolve_regions_and_report_errors( + &self, + region_context: DefId, + region_map: ®ion::ScopeTree, + outlives_env: &OutlivesEnvironment<'tcx>, + mode: RegionckMode, + ) { + assert!( + self.is_tainted_by_errors() || self.inner.borrow().region_obligations.is_empty(), + "region_obligations not empty: {:#?}", + self.inner.borrow().region_obligations + ); + let (var_infos, data) = self + .inner + .borrow_mut() + .region_constraints + .take() + .expect("regions already resolved") + .into_infos_and_data(); + + let region_rels = &RegionRelations::new( + self.tcx, + region_context, + region_map, + outlives_env.free_region_map(), + ); + + let (lexical_region_resolutions, errors) = + lexical_region_resolve::resolve(region_rels, var_infos, data, mode); + + let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); + assert!(old_value.is_none()); + + if !self.is_tainted_by_errors() { + // As a heuristic, just skip reporting region errors + // altogether if other errors have been reported while + // this infcx was in use. This is totally hokey but + // otherwise we have a hard time separating legit region + // errors from silly ones. + self.report_region_errors(region_map, &errors); + } + } + + /// Obtains (and clears) the current set of region + /// constraints. The inference context is still usable: further + /// unifications will simply add new constraints. + /// + /// This method is not meant to be used with normal lexical region + /// resolution. Rather, it is used in the NLL mode as a kind of + /// interim hack: basically we run normal type-check and generate + /// region constraints as normal, but then we take them and + /// translate them into the form that the NLL solver + /// understands. See the NLL module for mode details. + pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> { + assert!( + self.inner.borrow().region_obligations.is_empty(), + "region_obligations not empty: {:#?}", + self.inner.borrow().region_obligations + ); + + self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data() + } + + /// Gives temporary access to the region constraint data. + #[allow(non_camel_case_types)] // bug with impl trait + pub fn with_region_constraints( + &self, + op: impl FnOnce(&RegionConstraintData<'tcx>) -> R, + ) -> R { + let mut inner = self.inner.borrow_mut(); + op(inner.unwrap_region_constraints().data()) + } + + /// Takes ownership of the list of variable regions. This implies + /// that all the region constraints have already been taken, and + /// hence that `resolve_regions_and_report_errors` can never be + /// called. This is used only during NLL processing to "hand off" ownership + /// of the set of region variables into the NLL region context. + pub fn take_region_var_origins(&self) -> VarInfos { + let (var_infos, data) = self + .inner + .borrow_mut() + .region_constraints + .take() + .expect("regions already resolved") + .into_infos_and_data(); + assert!(data.is_empty()); + var_infos + } + + pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { + self.resolve_vars_if_possible(&t).to_string() + } + + pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { + let tstrs: Vec = ts.iter().map(|t| self.ty_to_string(*t)).collect(); + format!("({})", tstrs.join(", ")) + } + + pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String { + self.resolve_vars_if_possible(t).print_only_trait_path().to_string() + } + + /// If `TyVar(vid)` resolves to a type, return that type. Else, return the + /// universe index of `TyVar(vid)`. + pub fn probe_ty_var(&self, vid: TyVid) -> Result, ty::UniverseIndex> { + use self::type_variable::TypeVariableValue; + + match self.inner.borrow_mut().type_variables.probe(vid) { + TypeVariableValue::Known { value } => Ok(value), + TypeVariableValue::Unknown { universe } => Err(universe), + } + } + + /// Resolve any type variables found in `value` -- but only one + /// level. So, if the variable `?X` is bound to some type + /// `Foo`, then this would return `Foo` (but `?Y` may + /// itself be bound to a type). + /// + /// Useful when you only need to inspect the outermost level of + /// the type and don't care about nested types (or perhaps you + /// will be resolving them as well, e.g. in a loop). + pub fn shallow_resolve(&self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + let mut r = ShallowResolver::new(self); + value.fold_with(&mut r) + } + + pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid { + self.inner.borrow_mut().type_variables.root_var(var) + } + + /// Where possible, replaces type/const variables in + /// `value` with their final value. Note that region variables + /// are unaffected. If a type/const variable has not been unified, it + /// is left as is. This is an idempotent operation that does + /// not affect inference state in any way and so you can do it + /// at will. + pub fn resolve_vars_if_possible(&self, value: &T) -> T + where + T: TypeFoldable<'tcx>, + { + if !value.needs_infer() { + return value.clone(); // Avoid duplicated subst-folding. + } + let mut r = resolve::OpportunisticVarResolver::new(self); + value.fold_with(&mut r) + } + + /// Returns the first unresolved variable contained in `T`. In the + /// process of visiting `T`, this will resolve (where possible) + /// type variables in `T`, but it never constructs the final, + /// resolved type, so it's more efficient than + /// `resolve_vars_if_possible()`. + pub fn unresolved_type_vars(&self, value: &T) -> Option<(Ty<'tcx>, Option)> + where + T: TypeFoldable<'tcx>, + { + let mut r = resolve::UnresolvedTypeFinder::new(self); + value.visit_with(&mut r); + r.first_unresolved + } + + pub fn probe_const_var( + &self, + vid: ty::ConstVid<'tcx>, + ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> { + match self.inner.borrow_mut().const_unification_table.probe_value(vid).val { + ConstVariableValue::Known { value } => Ok(value), + ConstVariableValue::Unknown { universe } => Err(universe), + } + } + + pub fn fully_resolve>(&self, value: &T) -> FixupResult<'tcx, T> { + /*! + * Attempts to resolve all type/region/const variables in + * `value`. Region inference must have been run already (e.g., + * by calling `resolve_regions_and_report_errors`). If some + * variable was never unified, an `Err` results. + * + * This method is idempotent, but it not typically not invoked + * except during the writeback phase. + */ + + resolve::fully_resolve(self, value) + } + + // [Note-Type-error-reporting] + // An invariant is that anytime the expected or actual type is Error (the special + // error type, meaning that an error occurred when typechecking this expression), + // this is a derived error. The error cascaded from another error (that was already + // reported), so it's not useful to display it to the user. + // The following methods implement this logic. + // They check if either the actual or expected type is Error, and don't print the error + // in this case. The typechecker should only ever report type errors involving mismatched + // types using one of these methods, and should not call span_err directly for such + // errors. + + pub fn type_error_struct_with_diag( + &self, + sp: Span, + mk_diag: M, + actual_ty: Ty<'tcx>, + ) -> DiagnosticBuilder<'tcx> + where + M: FnOnce(String) -> DiagnosticBuilder<'tcx>, + { + let actual_ty = self.resolve_vars_if_possible(&actual_ty); + debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); + + // Don't report an error if actual type is `Error`. + if actual_ty.references_error() { + return self.tcx.sess.diagnostic().struct_dummy(); + } + + mk_diag(self.ty_to_string(actual_ty)) + } + + pub fn report_mismatched_types( + &self, + cause: &ObligationCause<'tcx>, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + err: TypeError<'tcx>, + ) -> DiagnosticBuilder<'tcx> { + let trace = TypeTrace::types(cause, true, expected, actual); + self.report_and_explain_type_error(trace, &err) + } + + pub fn replace_bound_vars_with_fresh_vars( + &self, + span: Span, + lbrct: LateBoundRegionConversionTime, + value: &ty::Binder, + ) -> (T, BTreeMap>) + where + T: TypeFoldable<'tcx>, + { + let fld_r = |br| self.next_region_var(LateBoundRegion(span, br, lbrct)); + let fld_t = |_| { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span, + }) + }; + let fld_c = |_, ty| { + self.next_const_var( + ty, + ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span }, + ) + }; + self.tcx.replace_bound_vars(value, fld_r, fld_t, fld_c) + } + + /// See the [`region_constraints::verify_generic_bound`] method. + pub fn verify_generic_bound( + &self, + origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + a: ty::Region<'tcx>, + bound: VerifyBound<'tcx>, + ) { + debug!("verify_generic_bound({:?}, {:?} <: {:?})", kind, a, bound); + + self.inner + .borrow_mut() + .unwrap_region_constraints() + .verify_generic_bound(origin, kind, a, bound); + } + + /// Obtains the latest type of the given closure; this may be a + /// closure in the current function, in which case its + /// `ClosureKind` may not yet be known. + pub fn closure_kind( + &self, + closure_def_id: DefId, + closure_substs: SubstsRef<'tcx>, + ) -> Option { + let closure_kind_ty = closure_substs.as_closure().kind_ty(closure_def_id, self.tcx); + let closure_kind_ty = self.shallow_resolve(closure_kind_ty); + closure_kind_ty.to_opt_closure_kind() + } + + /// Obtains the signature of a closure. For closures, unlike + /// `tcx.fn_sig(def_id)`, this method will work during the + /// type-checking of the enclosing function and return the closure + /// signature in its partially inferred state. + pub fn closure_sig(&self, def_id: DefId, substs: SubstsRef<'tcx>) -> ty::PolyFnSig<'tcx> { + let closure_sig_ty = substs.as_closure().sig_ty(def_id, self.tcx); + let closure_sig_ty = self.shallow_resolve(closure_sig_ty); + closure_sig_ty.fn_sig(self.tcx) + } + + /// Clears the selection, evaluation, and projection caches. This is useful when + /// repeatedly attempting to select an `Obligation` while changing only + /// its `ParamEnv`, since `FulfillmentContext` doesn't use probing. + pub fn clear_caches(&self) { + self.selection_cache.clear(); + self.evaluation_cache.clear(); + self.inner.borrow_mut().projection_cache.clear(); + } + + fn universe(&self) -> ty::UniverseIndex { + self.universe.get() + } + + /// Creates and return a fresh universe that extends all previous + /// universes. Updates `self.universe` to that new universe. + pub fn create_next_universe(&self) -> ty::UniverseIndex { + let u = self.universe.get().next_universe(); + self.universe.set(u); + u + } + + /// Resolves and evaluates a constant. + /// + /// The constant can be located on a trait like `::C`, in which case the given + /// substitutions and environment are used to resolve the constant. Alternatively if the + /// constant has generic parameters in scope the substitutions are used to evaluate the value of + /// the constant. For example in `fn foo() { let _ = [0; bar::()]; }` the repeat count + /// constant `bar::()` requires a substitution for `T`, if the substitution for `T` is still + /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is + /// returned. + /// + /// This handles inferences variables within both `param_env` and `substs` by + /// performing the operation on their respective canonical forms. + pub fn const_eval_resolve( + &self, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, + promoted: Option, + span: Option, + ) -> ConstEvalResult<'tcx> { + let mut original_values = OriginalQueryValues::default(); + let canonical = self.canonicalize_query(&(param_env, substs), &mut original_values); + + let (param_env, substs) = canonical.value; + // The return value is the evaluated value which doesn't contain any reference to inference + // variables, thus we don't need to substitute back the original values. + self.tcx.const_eval_resolve(param_env, def_id, substs, promoted, span) + } +} + +pub struct ShallowResolver<'a, 'tcx> { + infcx: &'a InferCtxt<'a, 'tcx>, +} + +impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { + #[inline(always)] + pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { + ShallowResolver { infcx } + } + + /// If `typ` is a type variable of some kind, resolve it one level + /// (but do not resolve types found in the result). If `typ` is + /// not a type variable, just return it unmodified. + pub fn shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> { + match typ.kind { + ty::Infer(ty::TyVar(v)) => { + // Not entirely obvious: if `typ` is a type variable, + // it can be resolved to an int/float variable, which + // can then be recursively resolved, hence the + // recursion. Note though that we prevent type + // variables from unifying to other type variables + // directly (though they may be embedded + // structurally), and we prevent cycles in any case, + // so this recursion should always be of very limited + // depth. + // + // Note: if these two lines are combined into one we get + // dynamic borrow errors on `self.infcx.inner`. + let known = self.infcx.inner.borrow_mut().type_variables.probe(v).known(); + known.map(|t| self.fold_ty(t)).unwrap_or(typ) + } + + ty::Infer(ty::IntVar(v)) => self + .infcx + .inner + .borrow_mut() + .int_unification_table + .probe_value(v) + .map(|v| v.to_type(self.infcx.tcx)) + .unwrap_or(typ), + + ty::Infer(ty::FloatVar(v)) => self + .infcx + .inner + .borrow_mut() + .float_unification_table + .probe_value(v) + .map(|v| v.to_type(self.infcx.tcx)) + .unwrap_or(typ), + + _ => typ, + } + } + + // `resolver.shallow_resolve_changed(ty)` is equivalent to + // `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always + // inlined, despite being large, because it has only two call sites that + // are extremely hot. + #[inline(always)] + pub fn shallow_resolve_changed(&self, infer: ty::InferTy) -> bool { + match infer { + ty::TyVar(v) => { + use self::type_variable::TypeVariableValue; + + // If `inlined_probe` returns a `Known` value its `kind` never + // matches `infer`. + match self.infcx.inner.borrow_mut().type_variables.inlined_probe(v) { + TypeVariableValue::Unknown { .. } => false, + TypeVariableValue::Known { .. } => true, + } + } + + ty::IntVar(v) => { + // If inlined_probe_value returns a value it's always a + // `ty::Int(_)` or `ty::UInt(_)`, which never matches a + // `ty::Infer(_)`. + self.infcx.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some() + } + + ty::FloatVar(v) => { + // If inlined_probe_value returns a value it's always a + // `ty::Float(_)`, which never matches a `ty::Infer(_)`. + // + // Not `inlined_probe_value(v)` because this call site is colder. + self.infcx.inner.borrow_mut().float_unification_table.probe_value(v).is_some() + } + + _ => unreachable!(), + } + } +} + +impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.shallow_resolve(ty) + } + + fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct { + self.infcx + .inner + .borrow_mut() + .const_unification_table + .probe_value(*vid) + .val + .known() + .unwrap_or(ct) + } else { + ct + } + } +} + +impl<'tcx> TypeTrace<'tcx> { + pub fn span(&self) -> Span { + self.cause.span + } + + pub fn types( + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Ty<'tcx>, + b: Ty<'tcx>, + ) -> TypeTrace<'tcx> { + TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) } + } + + pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> { + TypeTrace { + cause: ObligationCause::dummy(), + values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err }), + } + } +} + +impl<'tcx> SubregionOrigin<'tcx> { + pub fn span(&self) -> Span { + match *self { + Subtype(ref a) => a.span(), + InfStackClosure(a) => a, + InvokeClosure(a) => a, + DerefPointer(a) => a, + ClosureCapture(a, _) => a, + IndexSlice(a) => a, + RelateObjectBound(a) => a, + RelateParamBound(a, _) => a, + RelateRegionParamBound(a) => a, + RelateDefaultParamBound(a, _) => a, + Reborrow(a) => a, + ReborrowUpvar(a, _) => a, + DataBorrowed(_, a) => a, + ReferenceOutlivesReferent(_, a) => a, + ParameterInScope(_, a) => a, + ExprTypeIsNotInScope(_, a) => a, + BindingTypeIsNotValidAtDecl(a) => a, + CallRcvr(a) => a, + CallArg(a) => a, + CallReturn(a) => a, + Operand(a) => a, + AddrOf(a) => a, + AutoBorrow(a) => a, + SafeDestructor(a) => a, + CompareImplMethodObligation { span, .. } => span, + } + } + + pub fn from_obligation_cause(cause: &traits::ObligationCause<'tcx>, default: F) -> Self + where + F: FnOnce() -> Self, + { + match cause.code { + traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => { + SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span) + } + + traits::ObligationCauseCode::CompareImplMethodObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + } => SubregionOrigin::CompareImplMethodObligation { + span: cause.span, + item_name, + impl_item_def_id, + trait_item_def_id, + }, + + _ => default(), + } + } +} + +impl RegionVariableOrigin { + pub fn span(&self) -> Span { + match *self { + MiscVariable(a) => a, + PatternRegion(a) => a, + AddrOfRegion(a) => a, + Autoref(a) => a, + Coercion(a) => a, + EarlyBoundRegion(a, ..) => a, + LateBoundRegion(a, ..) => a, + BoundRegionInCoherence(_) => rustc_span::DUMMY_SP, + UpvarRegion(_, a) => a, + NLL(..) => bug!("NLL variable used with `span`"), + } + } +} + +impl<'tcx> fmt::Debug for RegionObligation<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "RegionObligation(sub_region={:?}, sup_type={:?})", + self.sub_region, self.sup_type + ) + } +} diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs similarity index 99% rename from src/librustc/infer/nll_relate/mod.rs rename to src/librustc_infer/infer/nll_relate/mod.rs index 77e20e6ad8f..50bea300c50 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc_infer/infer/nll_relate/mod.rs @@ -24,11 +24,11 @@ use crate::infer::InferCtxt; use crate::infer::{ConstVarValue, ConstVariableValue}; use crate::traits::DomainGoal; -use crate::ty::error::TypeError; -use crate::ty::fold::{TypeFoldable, TypeVisitor}; -use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::subst::GenericArg; -use crate::ty::{self, InferConst, Ty, TyCtxt}; +use rustc::ty::error::TypeError; +use rustc::ty::fold::{TypeFoldable, TypeVisitor}; +use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use rustc::ty::subst::GenericArg; +use rustc::ty::{self, InferConst, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; use std::fmt::Debug; @@ -340,7 +340,7 @@ where // In NLL, we don't have type inference variables // floating around, so we can do this rather imprecise // variant of the occurs-check. - assert!(!generalized_ty.has_infer_types()); + assert!(!generalized_ty.has_infer_types_or_consts()); } self.infcx.inner.borrow_mut().type_variables.instantiate(vid, generalized_ty); diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc_infer/infer/outlives/env.rs similarity index 83% rename from src/librustc/infer/outlives/env.rs rename to src/librustc_infer/infer/outlives/env.rs index ee2e629c2fc..6c1e86bf408 100644 --- a/src/librustc/infer/outlives/env.rs +++ b/src/librustc_infer/infer/outlives/env.rs @@ -1,10 +1,11 @@ use crate::infer::{GenericKind, InferCtxt}; -use crate::traits::query::outlives_bounds::{self, OutlivesBound}; -use crate::ty::free_region_map::FreeRegionMap; -use crate::ty::{self, Ty}; +use crate::traits::query::OutlivesBound; +use rustc::ty; +use rustc::ty::free_region_map::FreeRegionMap; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_span::Span; + +use super::explicit_outlives_bounds; /// The `OutlivesEnvironment` collects information about what outlives /// what in a given type-checking setting. For example, if we have a @@ -76,7 +77,7 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { region_bound_pairs_accum: vec![], }; - env.add_outlives_bounds(None, outlives_bounds::explicit_outlives_bounds(param_env)); + env.add_outlives_bounds(None, explicit_outlives_bounds(param_env)); env } @@ -142,39 +143,6 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { self.region_bound_pairs_accum.truncate(len); } - /// This method adds "implied bounds" into the outlives environment. - /// Implied bounds are outlives relationships that we can deduce - /// on the basis that certain types must be well-formed -- these are - /// either the types that appear in the function signature or else - /// the input types to an impl. For example, if you have a function - /// like - /// - /// ``` - /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { } - /// ``` - /// - /// we can assume in the caller's body that `'b: 'a` and that `T: - /// 'b` (and hence, transitively, that `T: 'a`). This method would - /// add those assumptions into the outlives-environment. - /// - /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs` - pub fn add_implied_bounds( - &mut self, - infcx: &InferCtxt<'a, 'tcx>, - fn_sig_tys: &[Ty<'tcx>], - body_id: hir::HirId, - span: Span, - ) { - debug!("add_implied_bounds()"); - - for &ty in fn_sig_tys { - let ty = infcx.resolve_vars_if_possible(&ty); - debug!("add_implied_bounds: ty = {}", ty); - let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); - self.add_outlives_bounds(Some(infcx), implied_bounds) - } - } - /// Save the current set of region-bound pairs under the given `body_id`. pub fn save_implied_bounds(&mut self, body_id: hir::HirId) { let old = @@ -188,8 +156,11 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { /// contain inference variables, it must be supplied, in which /// case we will register "givens" on the inference context. (See /// `RegionConstraintData`.) - fn add_outlives_bounds(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I) - where + pub fn add_outlives_bounds( + &mut self, + infcx: Option<&InferCtxt<'a, 'tcx>>, + outlives_bounds: I, + ) where I: IntoIterator>, { // Record relationships such as `T:'x` that don't go into the diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs new file mode 100644 index 00000000000..75cf742de31 --- /dev/null +++ b/src/librustc_infer/infer/outlives/mod.rs @@ -0,0 +1,27 @@ +//! Various code related to computing outlives relations. + +pub mod env; +pub mod obligations; +pub mod verify; + +use rustc::traits::query::OutlivesBound; +use rustc::ty; + +pub fn explicit_outlives_bounds<'tcx>( + param_env: ty::ParamEnv<'tcx>, +) -> impl Iterator> + 'tcx { + debug!("explicit_outlives_bounds()"); + param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate { + ty::Predicate::Projection(..) + | ty::Predicate::Trait(..) + | ty::Predicate::Subtype(..) + | ty::Predicate::WellFormed(..) + | ty::Predicate::ObjectSafe(..) + | ty::Predicate::ClosureKind(..) + | ty::Predicate::TypeOutlives(..) + | ty::Predicate::ConstEvaluatable(..) => None, + ty::Predicate::RegionOutlives(ref data) => data + .no_bound_vars() + .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), + }) +} diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc_infer/infer/outlives/obligations.rs similarity index 99% rename from src/librustc/infer/outlives/obligations.rs rename to src/librustc_infer/infer/outlives/obligations.rs index 17153ef9724..e3790b02734 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc_infer/infer/outlives/obligations.rs @@ -63,11 +63,13 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound}; use crate::traits::ObligationCause; -use crate::ty::outlives::Component; -use crate::ty::subst::GenericArgKind; -use crate::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::outlives::Component; +use rustc::ty::subst::GenericArgKind; +use rustc::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; + use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; +use smallvec::smallvec; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Registers that the given region obligation must be resolved diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc_infer/infer/outlives/verify.rs similarity index 99% rename from src/librustc/infer/outlives/verify.rs rename to src/librustc_infer/infer/outlives/verify.rs index a2c99064caa..08f73d2c9d2 100644 --- a/src/librustc/infer/outlives/verify.rs +++ b/src/librustc_infer/infer/outlives/verify.rs @@ -1,11 +1,13 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::{GenericKind, VerifyBound}; use crate::traits; -use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::{InternalSubsts, Subst}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc_data_structures::captures::Captures; use rustc_hir::def_id::DefId; +use smallvec::smallvec; + /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` /// obligation into a series of `'a: 'b` constraints and "verifys", as /// described on the module comment. The final constraints are emitted @@ -138,7 +140,6 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // Extend with bounds that we can find from the trait. let trait_bounds = self .projection_declared_bounds_from_trait(projection_ty) - .into_iter() .map(|r| VerifyBound::OutlivedBy(r)); // see the extensive comment in projection_must_outlive diff --git a/src/librustc_infer/infer/region_constraints/README.md b/src/librustc_infer/infer/region_constraints/README.md new file mode 100644 index 00000000000..0231dd06677 --- /dev/null +++ b/src/librustc_infer/infer/region_constraints/README.md @@ -0,0 +1,3 @@ +For info on how the current borrowck works, see the [rustc dev guide]. + +[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html diff --git a/src/librustc/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs similarity index 96% rename from src/librustc/infer/region_constraints/leak_check.rs rename to src/librustc_infer/infer/region_constraints/leak_check.rs index 29290cef2d2..6ebe3f57597 100644 --- a/src/librustc/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -1,7 +1,7 @@ use super::*; use crate::infer::{CombinedSnapshot, PlaceholderMap}; -use crate::ty::error::TypeError; -use crate::ty::relate::RelateResult; +use rustc::ty::error::TypeError; +use rustc::ty::relate::RelateResult; impl<'tcx> RegionConstraintCollector<'tcx> { /// Searches region constraints created since `snapshot` that @@ -34,7 +34,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { assert!(self.in_snapshot()); // Go through each placeholder that we created. - for (_, &placeholder_region) in placeholder_map { + for &placeholder_region in placeholder_map.values() { // Find the universe this placeholder inhabits. let placeholder = match placeholder_region { ty::RePlaceholder(p) => p, @@ -85,7 +85,7 @@ impl<'tcx> TaintSet<'tcx> { fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self { let mut regions = FxHashSet::default(); regions.insert(initial_region); - TaintSet { directions: directions, regions: regions } + TaintSet { directions, regions } } fn fixed_point( diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs similarity index 99% rename from src/librustc/infer/region_constraints/mod.rs rename to src/librustc_infer/infer/region_constraints/mod.rs index 8379a73bb9e..868b9504379 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -6,10 +6,10 @@ use self::UndoLog::*; use super::unify_key; use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin}; -use crate::ty::ReStatic; -use crate::ty::{self, Ty, TyCtxt}; -use crate::ty::{ReLateBound, ReVar}; -use crate::ty::{Region, RegionVid}; +use rustc::ty::ReStatic; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{ReLateBound, ReVar}; +use rustc::ty::{Region, RegionVid}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::unify as ut; @@ -23,7 +23,7 @@ use std::{cmp, fmt, mem}; mod leak_check; -pub use rustc::infer::types::MemberConstraint; +pub use rustc::infer::MemberConstraint; #[derive(Default)] pub struct RegionConstraintCollector<'tcx> { @@ -587,7 +587,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { // skip no-op cases known to be satisfied if let VerifyBound::AllBounds(ref bs) = verify.bound { - if bs.len() == 0 { + if bs.is_empty() { return; } } @@ -766,7 +766,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { b: Region<'tcx>, origin: SubregionOrigin<'tcx>, ) -> Region<'tcx> { - let vars = TwoRegions { a: a, b: b }; + let vars = TwoRegions { a, b }; if let Some(&c) = self.combine_map(t).get(&vars) { return tcx.mk_region(ReVar(c)); } diff --git a/src/librustc/infer/resolve.rs b/src/librustc_infer/infer/resolve.rs similarity index 96% rename from src/librustc/infer/resolve.rs rename to src/librustc_infer/infer/resolve.rs index c9acd1cf4a1..ce0f2f40894 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc_infer/infer/resolve.rs @@ -1,7 +1,7 @@ use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use super::{FixupError, FixupResult, InferCtxt, Span}; -use crate::ty::fold::{TypeFolder, TypeVisitor}; -use crate::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::fold::{TypeFolder, TypeVisitor}; +use rustc::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; /////////////////////////////////////////////////////////////////////////// // OPPORTUNISTIC VAR RESOLVER @@ -28,7 +28,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.has_infer_types() && !t.has_infer_consts() { + if !t.has_infer_types_or_consts() { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { let t = self.infcx.shallow_resolve(t); @@ -37,7 +37,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> { } fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> { - if !ct.has_infer_consts() { + if !ct.has_infer_types_or_consts() { ct // micro-optimize -- if there is nothing in this const that this fold affects... } else { let ct = self.infcx.shallow_resolve(ct); @@ -160,7 +160,7 @@ pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: &T) -> Fix where T: TypeFoldable<'tcx>, { - let mut full_resolver = FullTypeResolver { infcx: infcx, err: None }; + let mut full_resolver = FullTypeResolver { infcx, err: None }; let result = value.fold_with(&mut full_resolver); match full_resolver.err { None => Ok(result), @@ -169,7 +169,7 @@ where } // N.B. This type is not public because the protocol around checking the -// `err` field is not enforcable otherwise. +// `err` field is not enforceable otherwise. struct FullTypeResolver<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, err: Option>, diff --git a/src/librustc/infer/sub.rs b/src/librustc_infer/infer/sub.rs similarity index 96% rename from src/librustc/infer/sub.rs rename to src/librustc_infer/infer/sub.rs index ef4903358d5..f6fc38b5358 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc_infer/infer/sub.rs @@ -2,10 +2,10 @@ use super::combine::{CombineFields, RelationDir}; use super::SubregionOrigin; use crate::traits::Obligation; -use crate::ty::fold::TypeFoldable; -use crate::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; -use crate::ty::TyVar; -use crate::ty::{self, Ty, TyCtxt}; +use rustc::ty::fold::TypeFoldable; +use rustc::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; +use rustc::ty::TyVar; +use rustc::ty::{self, Ty, TyCtxt}; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. @@ -19,7 +19,7 @@ impl<'combine, 'infcx, 'tcx> Sub<'combine, 'infcx, 'tcx> { f: &'combine mut CombineFields<'infcx, 'tcx>, a_is_expected: bool, ) -> Sub<'combine, 'infcx, 'tcx> { - Sub { fields: f, a_is_expected: a_is_expected } + Sub { fields: f, a_is_expected } } fn with_expected_switched R>(&mut self, f: F) -> R { diff --git a/src/librustc/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs similarity index 99% rename from src/librustc/infer/type_variable.rs rename to src/librustc_infer/infer/type_variable.rs index f391a054a2a..b59c5606691 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -1,4 +1,4 @@ -use crate::ty::{self, Ty, TyVid}; +use rustc::ty::{self, Ty, TyVid}; use rustc_hir::def_id::DefId; use rustc_span::symbol::Symbol; use rustc_span::Span; diff --git a/src/librustc_infer/lib.rs b/src/librustc_infer/lib.rs new file mode 100644 index 00000000000..cb8ae8c592b --- /dev/null +++ b/src/librustc_infer/lib.rs @@ -0,0 +1,36 @@ +//! This crates defines the type inference engine. +//! +//! - **Type inference.** The type inference code can be found in the `infer` module; +//! this code handles low-level equality and subtyping operations. The +//! type check pass in the compiler is found in the `librustc_typeck` crate. +//! +//! For more information about how rustc works, see the [rustc dev guide]. +//! +//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/ +//! +//! # Note +//! +//! This API is completely unstable and subject to change. + +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![feature(bool_to_option)] +#![feature(box_patterns)] +#![feature(box_syntax)] +#![feature(never_type)] +#![feature(range_is_empty)] +#![feature(in_band_lifetimes)] +#![feature(crate_visibility_modifier)] +#![recursion_limit = "512"] // For rustdoc + +#[macro_use] +extern crate rustc_macros; +#[cfg(target_arch = "x86_64")] +#[macro_use] +extern crate rustc_data_structures; +#[macro_use] +extern crate log; +#[macro_use] +extern crate rustc; + +pub mod infer; +pub mod traits; diff --git a/src/librustc/traits/engine.rs b/src/librustc_infer/traits/engine.rs similarity index 84% rename from src/librustc/traits/engine.rs rename to src/librustc_infer/traits/engine.rs index 84bfc86e6a9..9ad722342a1 100644 --- a/src/librustc/traits/engine.rs +++ b/src/librustc_infer/traits/engine.rs @@ -1,9 +1,9 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; -use crate::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc::ty::{self, ToPredicate, Ty, WithConstness}; use rustc_hir::def_id::DefId; -use super::{ChalkFulfillmentContext, FulfillmentContext, FulfillmentError}; +use super::FulfillmentError; use super::{ObligationCause, PredicateObligation}; pub trait TraitEngine<'tcx>: 'tcx { @@ -76,13 +76,3 @@ impl> TraitEngineExt<'tcx> for T { } } } - -impl dyn TraitEngine<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> Box { - if tcx.sess.opts.debugging_opts.chalk { - Box::new(ChalkFulfillmentContext::new()) - } else { - Box::new(FulfillmentContext::new()) - } - } -} diff --git a/src/librustc_infer/traits/error_reporting/mod.rs b/src/librustc_infer/traits/error_reporting/mod.rs new file mode 100644 index 00000000000..8943ce4e6c5 --- /dev/null +++ b/src/librustc_infer/traits/error_reporting/mod.rs @@ -0,0 +1,106 @@ +use super::ObjectSafetyViolation; + +use crate::infer::InferCtxt; +use rustc::ty::TyCtxt; +use rustc_ast::ast; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_span::Span; +use std::fmt; + +impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + pub fn report_extra_impl_obligation( + &self, + error_span: Span, + item_name: ast::Name, + _impl_item_def_id: DefId, + trait_item_def_id: DefId, + requirement: &dyn fmt::Display, + ) -> DiagnosticBuilder<'tcx> { + let msg = "impl has stricter requirements than trait"; + let sp = self.tcx.sess.source_map().def_span(error_span); + + let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg); + + if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) { + let span = self.tcx.sess.source_map().def_span(trait_item_span); + err.span_label(span, format!("definition of `{}` from trait", item_name)); + } + + err.span_label(sp, format!("impl has extra requirement {}", requirement)); + + err + } +} + +pub fn report_object_safety_error( + tcx: TyCtxt<'tcx>, + span: Span, + trait_def_id: DefId, + violations: Vec, +) -> DiagnosticBuilder<'tcx> { + let trait_str = tcx.def_path_str(trait_def_id); + let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { + hir::Node::Item(item) => Some(item.ident.span), + _ => None, + }); + let span = tcx.sess.source_map().def_span(span); + let mut err = struct_span_err!( + tcx.sess, + span, + E0038, + "the trait `{}` cannot be made into an object", + trait_str + ); + err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str)); + + let mut reported_violations = FxHashSet::default(); + let mut had_span_label = false; + for violation in violations { + if let ObjectSafetyViolation::SizedSelf(sp) = &violation { + if !sp.is_empty() { + // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations + // with a `Span`. + reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); + } + } + if reported_violations.insert(violation.clone()) { + let spans = violation.spans(); + let msg = if trait_span.is_none() || spans.is_empty() { + format!("the trait cannot be made into an object because {}", violation.error_msg()) + } else { + had_span_label = true; + format!("...because {}", violation.error_msg()) + }; + if spans.is_empty() { + err.note(&msg); + } else { + for span in spans { + err.span_label(span, &msg); + } + } + match (trait_span, violation.solution()) { + (Some(_), Some((note, None))) => { + err.help(¬e); + } + (Some(_), Some((note, Some((sugg, span))))) => { + err.span_suggestion(span, ¬e, sugg, Applicability::MachineApplicable); + } + // Only provide the help if its a local trait, otherwise it's not actionable. + _ => {} + } + } + } + if let (Some(trait_span), true) = (trait_span, had_span_label) { + err.span_label(trait_span, "this trait cannot be made into an object..."); + } + + if tcx.sess.trait_methods_not_found.borrow().contains(&span) { + // Avoid emitting error caused by non-existing method (#58734) + err.cancel(); + } + + err +} diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs new file mode 100644 index 00000000000..1c0785497be --- /dev/null +++ b/src/librustc_infer/traits/mod.rs @@ -0,0 +1,136 @@ +//! Trait Resolution. See the [rustc guide] for more information on how this works. +//! +//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html + +mod engine; +pub mod error_reporting; +mod project; +mod structural_impls; +mod util; + +use rustc::ty::error::{ExpectedFound, TypeError}; +use rustc::ty::{self, Ty}; +use rustc_hir as hir; +use rustc_span::Span; + +pub use self::FulfillmentErrorCode::*; +pub use self::ObligationCauseCode::*; +pub use self::SelectionError::*; +pub use self::Vtable::*; + +pub use self::engine::{TraitEngine, TraitEngineExt}; +pub use self::project::MismatchedProjectionTypes; +pub use self::project::{ + Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, + ProjectionCacheSnapshot, Reveal, +}; +crate use self::util::elaborate_predicates; + +pub use rustc::traits::*; + +/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for +/// which the vtable must be found. The process of finding a vtable is +/// called "resolving" the `Obligation`. This process consists of +/// either identifying an `impl` (e.g., `impl Eq for int`) that +/// provides the required vtable, or else finding a bound that is in +/// scope. The eventual result is usually a `Selection` (defined below). +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct Obligation<'tcx, T> { + /// The reason we have to prove this thing. + pub cause: ObligationCause<'tcx>, + + /// The environment in which we should prove this thing. + pub param_env: ty::ParamEnv<'tcx>, + + /// The thing we are trying to prove. + pub predicate: T, + + /// If we started proving this as a result of trying to prove + /// something else, track the total depth to ensure termination. + /// If this goes over a certain threshold, we abort compilation -- + /// in such cases, we can not say whether or not the predicate + /// holds for certain. Stupid halting problem; such a drag. + pub recursion_depth: usize, +} + +pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; +pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; + +// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert_size!(PredicateObligation<'_>, 112); + +pub type Obligations<'tcx, O> = Vec>; +pub type PredicateObligations<'tcx> = Vec>; +pub type TraitObligations<'tcx> = Vec>; + +pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; + +pub struct FulfillmentError<'tcx> { + pub obligation: PredicateObligation<'tcx>, + pub code: FulfillmentErrorCode<'tcx>, + /// Diagnostics only: we opportunistically change the `code.span` when we encounter an + /// obligation error caused by a call argument. When this is the case, we also signal that in + /// this field to ensure accuracy of suggestions. + pub points_at_arg_span: bool, +} + +#[derive(Clone)] +pub enum FulfillmentErrorCode<'tcx> { + CodeSelectionError(SelectionError<'tcx>), + CodeProjectionError(MismatchedProjectionTypes<'tcx>), + CodeSubtypeError(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate + CodeAmbiguity, +} + +impl<'tcx, O> Obligation<'tcx, O> { + pub fn new( + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + predicate: O, + ) -> Obligation<'tcx, O> { + Obligation { cause, param_env, recursion_depth: 0, predicate } + } + + pub fn with_depth( + cause: ObligationCause<'tcx>, + recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, + predicate: O, + ) -> Obligation<'tcx, O> { + Obligation { cause, param_env, recursion_depth, predicate } + } + + pub fn misc( + span: Span, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + trait_ref: O, + ) -> Obligation<'tcx, O> { + Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref) + } + + pub fn with

Version {}

\ \

Back to index

", - crate_name, version + crate_name, + Escape(version), ) } else { String::new() @@ -1541,7 +1594,7 @@ impl Context { } if self.shared.sort_modules_alphabetically { - for (_, items) in &mut map { + for items in map.values_mut() { items.sort(); } } @@ -1564,7 +1617,7 @@ impl Context { let mut path = String::new(); - // We can safely ignore macros from other libraries + // We can safely ignore synthetic `SourceFile`s. let file = match item.source.filename { FileName::Real(ref path) => path, _ => return None, @@ -2324,7 +2377,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func f.generics.print() ) .len(); - write!(w, "{}
", render_spotlight_traits(it));
+    write!(w, "
");
     render_attributes(w, it, false);
     write!(
         w,
@@ -2527,13 +2580,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait)
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
         let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
-        write!(
-            w,
-            "

{extra}", - extra = render_spotlight_traits(m), - id = id, - ns_id = ns_id - ); + write!(w, "

", id = id, ns_id = ns_id); render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); write!(w, ""); render_stability_since(w, m, t); @@ -2726,7 +2773,7 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>) -> String { let name = it.name.as_ref().unwrap(); let ty = match it.type_() { Typedef | AssocType => AssocType, - s @ _ => s, + s => s, }; let anchor = format!("#{}.{}", ty, name); @@ -2783,7 +2830,7 @@ fn assoc_type( fn render_stability_since_raw(w: &mut Buffer, ver: Option<&str>, containing_ver: Option<&str>) { if let Some(v) = ver { - if containing_ver != ver && v.len() > 0 { + if containing_ver != ver && !v.is_empty() { write!(w, "{0}", v) } } @@ -3130,26 +3177,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) { render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -fn render_attribute(attr: &ast::MetaItem) -> Option { - let path = pprust::path_to_string(&attr.path); - - if attr.is_word() { - Some(path) - } else if let Some(v) = attr.value_str() { - Some(format!("{} = {:?}", path, v)) - } else if let Some(values) = attr.meta_item_list() { - let display: Vec<_> = values - .iter() - .filter_map(|attr| attr.meta_item().and_then(|mi| render_attribute(mi))) - .collect(); - - if display.len() > 0 { Some(format!("{}({})", path, display.join(", "))) } else { None } - } else { - None - } -} - -const ATTRIBUTE_WHITELIST: &'static [Symbol] = &[ +const ATTRIBUTE_WHITELIST: &[Symbol] = &[ sym::export_name, sym::lang, sym::link_section, @@ -3174,11 +3202,10 @@ fn render_attributes(w: &mut Buffer, it: &clean::Item, top: bool) { if !ATTRIBUTE_WHITELIST.contains(&attr.name_or_empty()) { continue; } - if let Some(s) = render_attribute(&attr.meta().unwrap()) { - attrs.push_str(&format!("#[{}]\n", s)); - } + + attrs.push_str(&pprust::attribute_to_string(&attr)); } - if attrs.len() > 0 { + if !attrs.is_empty() { write!( w, "{}", @@ -3400,10 +3427,8 @@ fn render_assoc_items( let deref_impl = traits.iter().find(|t| t.inner_impl().trait_.def_id() == c.deref_trait_did); if let Some(impl_) = deref_impl { - let has_deref_mut = traits - .iter() - .find(|t| t.inner_impl().trait_.def_id() == c.deref_mut_trait_did) - .is_some(); + let has_deref_mut = + traits.iter().any(|t| t.inner_impl().trait_.def_id() == c.deref_mut_trait_did); render_deref_methods(w, cx, impl_, containing_item, has_deref_mut); } @@ -3519,76 +3544,6 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool { } } -fn render_spotlight_traits(item: &clean::Item) -> String { - match item.inner { - clean::FunctionItem(clean::Function { ref decl, .. }) - | clean::TyMethodItem(clean::TyMethod { ref decl, .. }) - | clean::MethodItem(clean::Method { ref decl, .. }) - | clean::ForeignFunctionItem(clean::Function { ref decl, .. }) => spotlight_decl(decl), - _ => String::new(), - } -} - -fn spotlight_decl(decl: &clean::FnDecl) -> String { - let mut out = Buffer::html(); - let mut trait_ = String::new(); - - if let Some(did) = decl.output.def_id() { - let c = cache(); - if let Some(impls) = c.impls.get(&did) { - for i in impls { - let impl_ = i.inner_impl(); - if impl_.trait_.def_id().map_or(false, |d| c.traits[&d].is_spotlight) { - if out.is_empty() { - out.push_str(&format!( - "

Important traits for {}

\ - ", - impl_.for_.print() - )); - trait_.push_str(&impl_.for_.print().to_string()); - } - - //use the "where" class here to make it small - out.push_str(&format!( - "{}", - impl_.print() - )); - let t_did = impl_.trait_.def_id().unwrap(); - for it in &impl_.items { - if let clean::TypedefItem(ref tydef, _) = it.inner { - out.push_str(" "); - assoc_type( - &mut out, - it, - &[], - Some(&tydef.type_), - AssocItemLink::GotoSource(t_did, &FxHashSet::default()), - "", - ); - out.push_str(";"); - } - } - } - } - } - } - - if !out.is_empty() { - out.insert_str( - 0, - &format!( - "
ⓘ\ - Important traits for {}
\ -
", - trait_ - ), - ); - out.push_str("
"); - } - - out.into_inner() -} - fn render_impl( w: &mut Buffer, cx: &Context, @@ -3600,7 +3555,7 @@ fn render_impl( use_absolute: Option, is_on_foreign_type: bool, show_default_items: bool, - // This argument is used to reference same type with different pathes to avoid duplication + // This argument is used to reference same type with different paths to avoid duplication // in documentation pages for trait with automatic implementations like "Send" and "Sync". aliases: &[String], ) { @@ -3695,14 +3650,13 @@ fn render_impl( (true, " hidden") }; match item.inner { - clean::MethodItem(clean::Method { ref decl, .. }) - | clean::TyMethodItem(clean::TyMethod { ref decl, .. }) => { + clean::MethodItem(clean::Method { .. }) + | clean::TyMethodItem(clean::TyMethod { .. }) => { // Only render when the method is not static or we allow static methods if render_method_item { let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type, extra_class); - write!(w, "{}", spotlight_decl(decl)); write!(w, "", ns_id); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); write!(w, ""); @@ -3815,7 +3769,7 @@ fn render_impl( ) { for trait_item in &t.items { let n = trait_item.name.clone(); - if i.items.iter().find(|m| m.name == n).is_some() { + if i.items.iter().any(|m| m.name == n) { continue; } let did = i.trait_.as_ref().unwrap().def_id().unwrap(); @@ -3974,7 +3928,7 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer) { "
\

Version {}

\
", - version + Escape(version) ); } } @@ -4049,7 +4003,7 @@ fn get_next_url(used_links: &mut FxHashSet, url: String) -> String { return url; } let mut add = 1; - while used_links.insert(format!("{}-{}", url, add)) == false { + while !used_links.insert(format!("{}-{}", url, add)) { add += 1; } format!("{}-{}", url, add) @@ -4609,7 +4563,7 @@ fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item) { document(w, cx, it) } -crate const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang"; +crate const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang"; fn make_item_keywords(it: &clean::Item) -> String { format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap()) diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index f1f83acdda5..ed0de2b3119 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -12,7 +12,7 @@ use std::path::{Path, PathBuf}; use serde::Serialize; use super::{plain_summary_line, shorten, Impl, IndexItem, IndexItemFunctionType, ItemType}; -use super::{RenderInfo, Type}; +use super::{Generic, RenderInfo, RenderType, TypeWithKind}; /// Indicates where an external crate can be found. pub enum ExternalLocation { @@ -43,7 +43,7 @@ crate struct Cache { /// found on that implementation. pub impls: FxHashMap>, - /// Maintains a mapping of local crate `NodeId`s to the fully qualified name + /// Maintains a mapping of local crate `DefId`s to the fully qualified name /// and "short type description" of that node. This is used when generating /// URLs when a type is being linked to. External paths are not located in /// this map because the `External` type itself has all the information @@ -139,6 +139,7 @@ impl Cache { deref_trait_did, deref_mut_trait_did, owned_box_did, + .. } = renderinfo; let external_paths = @@ -358,6 +359,7 @@ impl DocFolder for Cache { | clean::ForeignTypeItem | clean::MacroItem(..) | clean::ProcMacroItem(..) + | clean::VariantItem(..) if !self.stripped_mod => { // Re-exported items mean that the same id can show up twice @@ -373,13 +375,6 @@ impl DocFolder for Cache { } self.add_aliases(&item); } - // Link variants to their parent enum because pages aren't emitted - // for each variant. - clean::VariantItem(..) if !self.stripped_mod => { - let mut stack = self.stack.clone(); - stack.pop(); - self.paths.insert(item.def_id, (stack, ItemType::Enum)); - } clean::PrimitiveItem(..) => { self.add_aliases(&item); @@ -396,7 +391,8 @@ impl DocFolder for Cache { | clean::EnumItem(..) | clean::ForeignTypeItem | clean::StructItem(..) - | clean::UnionItem(..) => { + | clean::UnionItem(..) + | clean::VariantItem(..) => { self.parent_stack.push(item.def_id); self.parent_is_trait_impl = false; true @@ -539,7 +535,7 @@ fn extern_location( if let Some(url) = extern_url { let mut url = url.to_string(); - if !url.ends_with("/") { + if !url.ends_with('/') { url.push('/'); } return Remote(url); @@ -553,7 +549,7 @@ fn extern_location( .filter_map(|a| a.value_str()) .map(|url| { let mut url = url.to_string(); - if !url.ends_with("/") { + if !url.ends_with('/') { url.push('/') } Remote(url) @@ -564,7 +560,7 @@ fn extern_location( /// Builds the search index from the collected metadata fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { - let mut nodeid_to_pathid = FxHashMap::default(); + let mut defid_to_pathid = FxHashMap::default(); let mut crate_items = Vec::with_capacity(cache.search_index.len()); let mut crate_paths = vec![]; @@ -586,23 +582,26 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { } } - // Reduce `NodeId` in paths into smaller sequential numbers, + // Reduce `DefId` in paths into smaller sequential numbers, // and prune the paths that do not appear in the index. let mut lastpath = String::new(); let mut lastpathid = 0usize; for item in search_index { - item.parent_idx = item.parent.map(|nodeid| { - if nodeid_to_pathid.contains_key(&nodeid) { - *nodeid_to_pathid.get(&nodeid).expect("no pathid") + item.parent_idx = item.parent.and_then(|defid| { + if defid_to_pathid.contains_key(&defid) { + defid_to_pathid.get(&defid).map(|x| *x) } else { let pathid = lastpathid; - nodeid_to_pathid.insert(nodeid, pathid); + defid_to_pathid.insert(defid, pathid); lastpathid += 1; - let &(ref fqp, short) = paths.get(&nodeid).unwrap(); - crate_paths.push((short, fqp.last().unwrap().clone())); - pathid + if let Some(&(ref fqp, short)) = paths.get(&defid) { + crate_paths.push((short, fqp.last().unwrap().clone())); + Some(pathid) + } else { + None + } } }); @@ -651,20 +650,25 @@ fn get_index_search_type(item: &clean::Item) -> Option { _ => return None, }; - let inputs = - all_types.iter().map(|arg| get_index_type(&arg)).filter(|a| a.name.is_some()).collect(); + let inputs = all_types + .iter() + .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind))) + .filter(|a| a.ty.name.is_some()) + .collect(); let output = ret_types .iter() - .map(|arg| get_index_type(&arg)) - .filter(|a| a.name.is_some()) + .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind))) + .filter(|a| a.ty.name.is_some()) .collect::>(); let output = if output.is_empty() { None } else { Some(output) }; Some(IndexItemFunctionType { inputs, output }) } -fn get_index_type(clean_type: &clean::Type) -> Type { - let t = Type { +fn get_index_type(clean_type: &clean::Type) -> RenderType { + let t = RenderType { + ty: clean_type.def_id(), + idx: None, name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()), generics: get_generics(clean_type), }; @@ -675,7 +679,7 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option match *clean_type { clean::ResolvedPath { ref path, .. } => { let segments = &path.segments; - let path_segment = segments.into_iter().last().unwrap_or_else(|| panic!( + let path_segment = segments.iter().last().unwrap_or_else(|| panic!( "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path", clean_type, accept_generic )); @@ -689,12 +693,17 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option } } -fn get_generics(clean_type: &clean::Type) -> Option> { +fn get_generics(clean_type: &clean::Type) -> Option> { clean_type.generics().and_then(|types| { let r = types .iter() - .filter_map(|t| get_index_type_name(t, false)) - .map(|s| s.to_ascii_lowercase()) + .filter_map(|t| { + if let Some(name) = get_index_type_name(t, false) { + Some(Generic { name: name.to_ascii_lowercase(), defid: t.def_id(), idx: None }) + } else { + None + } + }) .collect::>(); if r.is_empty() { None } else { Some(r) } }) diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 79e7d3d783b..86f46b2d7e1 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -35,7 +35,7 @@ impl<'a> DocFolder for SourceCollector<'a> { // If we're including source files, and we haven't seen this file yet, // then we need to render it out to the filesystem. if self.scx.include_sources - // skip all invalid or macro spans + // skip all synthetic "files" && item.source.filename.is_real() // skip non-local items && item.def_id.is_local() diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 44fd8b929f3..3f12fb893a4 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -341,7 +341,6 @@ function getSearchElement() { function handleEscape(ev) { var help = getHelpElement(); var search = getSearchElement(); - hideModal(); if (hasClass(help, "hidden") === false) { displayHelp(false, ev, help); } else if (hasClass(search, "hidden") === false) { @@ -373,7 +372,6 @@ function getSearchElement() { case "s": case "S": displayHelp(false, ev); - hideModal(); ev.preventDefault(); focusSearchBar(); break; @@ -386,7 +384,6 @@ function getSearchElement() { case "?": if (ev.shiftKey) { - hideModal(); displayHelp(true, ev); } break; @@ -526,13 +523,14 @@ function getSearchElement() { } function initSearch(rawSearchIndex) { - var currentResults, index, searchIndex; var MAX_LEV_DISTANCE = 3; var MAX_RESULTS = 200; var GENERICS_DATA = 1; var NAME = 0; var INPUTS_DATA = 0; var OUTPUT_DATA = 1; + var NO_TYPE_FILTER = -1; + var currentResults, index, searchIndex; var params = getQueryStringParams(); // Populate search bar with query string search term when provided, @@ -559,7 +557,7 @@ function getSearchElement() { return i; } } - return -1; + return NO_TYPE_FILTER; } var valLower = query.query.toLowerCase(), @@ -722,6 +720,13 @@ function getSearchElement() { }; } + function getObjectFromId(id) { + if (typeof id === "number") { + return searchIndex[id]; + } + return {'name': id}; + } + function checkGenerics(obj, val) { // The names match, but we need to be sure that all generics kinda // match as well. @@ -738,8 +743,10 @@ function getSearchElement() { for (var y = 0; y < vlength; ++y) { var lev = { pos: -1, lev: MAX_LEV_DISTANCE + 1}; var elength = elems.length; + var firstGeneric = getObjectFromId(val.generics[y]).name; for (var x = 0; x < elength; ++x) { - var tmp_lev = levenshtein(elems[x], val.generics[y]); + var tmp_lev = levenshtein(getObjectFromId(elems[x]).name, + firstGeneric); if (tmp_lev < lev.lev) { lev.lev = tmp_lev; lev.pos = x; @@ -774,8 +781,9 @@ function getSearchElement() { for (var y = 0; allFound === true && y < val.generics.length; ++y) { allFound = false; + var firstGeneric = getObjectFromId(val.generics[y]).name; for (x = 0; allFound === false && x < elems.length; ++x) { - allFound = elems[x] === val.generics[y]; + allFound = getObjectFromId(elems[x]).name === firstGeneric; } if (allFound === true) { elems.splice(x - 1, 1); @@ -832,16 +840,22 @@ function getSearchElement() { return lev_distance + 1; } - function findArg(obj, val, literalSearch) { + function findArg(obj, val, literalSearch, typeFilter) { var lev_distance = MAX_LEV_DISTANCE + 1; - if (obj && obj.type && obj.type[INPUTS_DATA] && - obj.type[INPUTS_DATA].length > 0) { + if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) { var length = obj.type[INPUTS_DATA].length; for (var i = 0; i < length; i++) { - var tmp = checkType(obj.type[INPUTS_DATA][i], val, literalSearch); - if (literalSearch === true && tmp === true) { - return true; + var tmp = obj.type[INPUTS_DATA][i]; + if (typePassesFilter(typeFilter, tmp[1]) === false) { + continue; + } + tmp = checkType(tmp, val, literalSearch); + if (literalSearch === true) { + if (tmp === true) { + return true; + } + continue; } lev_distance = Math.min(tmp, lev_distance); if (lev_distance === 0) { @@ -852,20 +866,20 @@ function getSearchElement() { return literalSearch === true ? false : lev_distance; } - function checkReturned(obj, val, literalSearch) { + function checkReturned(obj, val, literalSearch, typeFilter) { var lev_distance = MAX_LEV_DISTANCE + 1; if (obj && obj.type && obj.type.length > OUTPUT_DATA) { var ret = obj.type[OUTPUT_DATA]; - if (!obj.type[OUTPUT_DATA].length) { + if (typeof ret[0] === "string") { ret = [ret]; } for (var x = 0; x < ret.length; ++x) { - var r = ret[x]; - if (typeof r === "string") { - r = [r]; + var tmp = ret[x]; + if (typePassesFilter(typeFilter, tmp[1]) === false) { + continue; } - var tmp = checkType(r, val, literalSearch); + tmp = checkType(tmp, val, literalSearch); if (literalSearch === true) { if (tmp === true) { return true; @@ -920,7 +934,7 @@ function getSearchElement() { function typePassesFilter(filter, type) { // No filter - if (filter < 0) return true; + if (filter <= NO_TYPE_FILTER) return true; // Exact match if (filter === type) return true; @@ -929,11 +943,13 @@ function getSearchElement() { var name = itemTypes[type]; switch (itemTypes[filter]) { case "constant": - return (name == "associatedconstant"); + return name === "associatedconstant"; case "fn": - return (name == "method" || name == "tymethod"); + return name === "method" || name === "tymethod"; case "type": - return (name == "primitive" || name == "keyword"); + return name === "primitive" || name === "associatedtype"; + case "trait": + return name === "traitalias"; } // No match @@ -962,42 +978,33 @@ function getSearchElement() { if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) { continue; } - in_args = findArg(searchIndex[i], val, true); - returned = checkReturned(searchIndex[i], val, true); + in_args = findArg(searchIndex[i], val, true, typeFilter); + returned = checkReturned(searchIndex[i], val, true, typeFilter); ty = searchIndex[i]; fullId = generateId(ty); - if (searchWords[i] === val.name) { - // filter type: ... queries - if (typePassesFilter(typeFilter, searchIndex[i].ty) && - results[fullId] === undefined) - { - results[fullId] = {id: i, index: -1}; - } - } else if ((in_args === true || returned === true) && - typePassesFilter(typeFilter, searchIndex[i].ty)) { - if (in_args === true || returned === true) { - if (in_args === true) { - results_in_args[fullId] = { - id: i, - index: -1, - dontValidate: true, - }; - } - if (returned === true) { - results_returned[fullId] = { - id: i, - index: -1, - dontValidate: true, - }; - } - } else { - results[fullId] = { - id: i, - index: -1, - dontValidate: true, - }; - } + if (searchWords[i] === val.name + && typePassesFilter(typeFilter, searchIndex[i].ty) + && results[fullId] === undefined) { + results[fullId] = { + id: i, + index: -1, + dontValidate: true, + }; + } + if (in_args === true && results_in_args[fullId] === undefined) { + results_in_args[fullId] = { + id: i, + index: -1, + dontValidate: true, + }; + } + if (returned === true && results_returned[fullId] === undefined) { + results_returned[fullId] = { + id: i, + index: -1, + dontValidate: true, + }; } } query.inputs = [val]; @@ -1028,7 +1035,7 @@ function getSearchElement() { // allow searching for void (no output) functions as well var typeOutput = type.length > OUTPUT_DATA ? type[OUTPUT_DATA].name : ""; - returned = checkReturned(ty, output, true); + returned = checkReturned(ty, output, true, NO_TYPE_FILTER); if (output.name === "*" || returned === true) { in_args = false; var is_module = false; @@ -1129,16 +1136,8 @@ function getSearchElement() { lev += 1; } } - if ((in_args = findArg(ty, valGenerics)) <= MAX_LEV_DISTANCE) { - if (typePassesFilter(typeFilter, ty.ty) === false) { - in_args = MAX_LEV_DISTANCE + 1; - } - } - if ((returned = checkReturned(ty, valGenerics)) <= MAX_LEV_DISTANCE) { - if (typePassesFilter(typeFilter, ty.ty) === false) { - returned = MAX_LEV_DISTANCE + 1; - } - } + in_args = findArg(ty, valGenerics, false, typeFilter); + returned = checkReturned(ty, valGenerics, false, typeFilter); lev += lev_add; if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) { @@ -1364,14 +1363,15 @@ function getSearchElement() { var href; var type = itemTypes[item.ty]; var name = item.name; + var path = item.path; if (type === "mod") { - displayPath = item.path + "::"; - href = rootPath + item.path.replace(/::/g, "/") + "/" + + displayPath = path + "::"; + href = rootPath + path.replace(/::/g, "/") + "/" + name + "/index.html"; } else if (type === "primitive" || type === "keyword") { displayPath = ""; - href = rootPath + item.path.replace(/::/g, "/") + + href = rootPath + path.replace(/::/g, "/") + "/" + type + "." + name + ".html"; } else if (type === "externcrate") { displayPath = ""; @@ -1380,14 +1380,27 @@ function getSearchElement() { var myparent = item.parent; var anchor = "#" + type + "." + name; var parentType = itemTypes[myparent.ty]; + var pageType = parentType; + var pageName = myparent.name; + if (parentType === "primitive") { displayPath = myparent.name + "::"; + } else if (type === "structfield" && parentType === "variant") { + // Structfields belonging to variants are special: the + // final path element is the enum name. + var splitPath = item.path.split("::"); + var enumName = splitPath.pop(); + path = splitPath.join("::"); + displayPath = path + "::" + enumName + "::" + myparent.name + "::"; + anchor = "#variant." + myparent.name + ".field." + name; + pageType = "enum"; + pageName = enumName; } else { - displayPath = item.path + "::" + myparent.name + "::"; + displayPath = path + "::" + myparent.name + "::"; } - href = rootPath + item.path.replace(/::/g, "/") + - "/" + parentType + - "." + myparent.name + + href = rootPath + path.replace(/::/g, "/") + + "/" + pageType + + "." + pageName + ".html" + anchor; } else { displayPath = item.path + "::"; @@ -1668,7 +1681,7 @@ function getSearchElement() { // (String) name] var paths = rawSearchIndex[crate].p; - // convert `paths` into an object form + // convert `rawPaths` entries into object form var len = paths.length; for (i = 0; i < len; ++i) { paths[i] = {ty: paths[i][0], name: paths[i][1]}; @@ -2490,31 +2503,6 @@ function getSearchElement() { lineNumbersFunc(e); }); - function showModal(content) { - var modal = document.createElement("div"); - modal.id = "important"; - addClass(modal, "modal"); - modal.innerHTML = "
✕" + - "
" + content + - "
"; - document.getElementsByTagName("body")[0].appendChild(modal); - document.getElementById("modal-close").onclick = hideModal; - modal.onclick = hideModal; - } - - function hideModal() { - var modal = document.getElementById("important"); - if (modal) { - modal.parentNode.removeChild(modal); - } - } - - onEachLazy(document.getElementsByClassName("important-traits"), function(e) { - e.onclick = function() { - showModal(e.lastElementChild.innerHTML); - }; - }); - // In the search display, allows to switch between tabs. function printTab(nb) { if (nb === 0 || nb === 1 || nb === 2) { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 0dfe82c5014..8887bca3c59 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -143,12 +143,9 @@ code, pre, a.test-arrow { border-radius: 3px; padding: 0 0.1em; } -.docblock pre code, .docblock-short pre code, .docblock code.spotlight { +.docblock pre code, .docblock-short pre code { padding: 0; } -.docblock code.spotlight :last-child { - padding-bottom: 0.6em; -} pre { padding: 14px; } @@ -503,7 +500,7 @@ h4 > code, h3 > code, .invisible > code { font-size: 0.8em; } -.content .methods > div:not(.important-traits) { +.content .methods > div { margin-left: 40px; margin-bottom: 15px; } @@ -1035,7 +1032,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { .information { position: absolute; - left: -20px; + left: -25px; margin-top: 7px; z-index: 1; } @@ -1050,12 +1047,13 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { width: 120px; display: none; text-align: center; - padding: 5px 3px; + padding: 5px 3px 3px 3px; border-radius: 6px; margin-left: 5px; top: -5px; left: 105%; z-index: 10; + font-size: 16px; } .tooltip:hover .tooltiptext { @@ -1066,14 +1064,20 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { content: " "; position: absolute; top: 50%; - left: 11px; + left: 16px; margin-top: -5px; border-width: 5px; border-style: solid; } -.important-traits .tooltip .tooltiptext { +.tooltip.compile_fail, .tooltip.ignore { + font-weight: bold; + font-size: 20px; +} + +.tooltip .tooltiptext { border: 1px solid; + font-weight: normal; } pre.rust { @@ -1117,17 +1121,6 @@ pre.rust { font-size: 16px; } -.important-traits { - cursor: pointer; - z-index: 2; -} - -h4 > .important-traits { - position: absolute; - left: -44px; - top: 2px; -} - #all-types { text-align: center; border: 1px solid; @@ -1354,12 +1347,6 @@ h4 > .important-traits { z-index: 1; } - h4 > .important-traits { - position: absolute; - left: -22px; - top: 24px; - } - #titles > div > div.count { float: left; width: 100%; @@ -1462,82 +1449,12 @@ h4 > .important-traits { } } -.modal { - position: fixed; - width: 100vw; - height: 100vh; - z-index: 10000; - top: 0; - left: 0; -} - -.modal-content { - display: block; - max-width: 60%; - min-width: 200px; - padding: 8px; - top: 40%; - position: absolute; - left: 50%; - transform: translate(-50%, -40%); - border: 1px solid; - border-radius: 4px; - border-top-right-radius: 0; -} - -.modal-content > .docblock { - margin: 0; -} - h3.important { margin: 0; margin-bottom: 13px; font-size: 19px; } -.modal-content > .docblock > code.content { - margin: 0; - padding: 0; - font-size: 20px; -} - -.modal-content > .close { - position: absolute; - font-weight: 900; - right: -25px; - top: -1px; - font-size: 18px; - width: 25px; - padding-right: 2px; - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; - text-align: center; - border: 1px solid; - border-right: 0; - cursor: pointer; -} - -.modal-content > .whiter { - height: 25px; - position: absolute; - width: 3px; - right: -2px; - top: 0px; -} - -#main > div.important-traits { - position: absolute; - left: -24px; - margin-top: 16px; -} - -.content > .methods > .method > div.important-traits { - position: absolute; - font-weight: 400; - left: -42px; - margin-top: 2px; -} - kbd { display: inline-block; padding: 3px 5px; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 9a0e7bbabcb..ff32a0fa09e 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -254,7 +254,7 @@ a.test-arrow:hover{ } pre.compile_fail { - border-left: 2px solid rgba(255,0,0,.6); + border-left: 2px solid rgba(255,0,0,.8); } pre.compile_fail:hover, .information:hover + pre.compile_fail { @@ -270,7 +270,7 @@ pre.ignore:hover, .information:hover + pre.ignore { } .tooltip.compile_fail { - color: rgba(255,0,0,.6); + color: rgba(255,0,0,.8); } .information > .compile_fail:hover { @@ -282,7 +282,7 @@ pre.ignore:hover, .information:hover + pre.ignore { } .information > .ignore:hover { - color: rgba(255,142,0,1); + color: #ff9200; } .search-failed a { @@ -290,20 +290,15 @@ pre.ignore:hover, .information:hover + pre.ignore { } .tooltip .tooltiptext { - background-color: black; + background-color: #000; color: #fff; + border-color: #000; } .tooltip .tooltiptext::after { border-color: transparent black transparent transparent; } -.important-traits .tooltip .tooltiptext { - background-color: white; - color: black; - border-color: black; -} - #titles > div:not(.selected) { background-color: #252525; border-top-color: #252525; @@ -317,33 +312,6 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #888; } -.modal { - background-color: rgba(0,0,0,0.3); -} - -.modal-content { - background-color: #272727; - border-color: #999; -} - -.modal-content > .close { - background-color: #272727; - border-color: #999; -} - -.modal-content > .close:hover { - background-color: #ff1f1f; - color: white; -} - -.modal-content > .whiter { - background-color: #272727; -} - -.modal-content > .close:hover + .whiter { - background-color: #ff1f1f; -} - @media (max-width: 700px) { .sidebar-menu { background-color: #505050; diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index ca8ea1c456a..2b2819f7126 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -248,7 +248,7 @@ a.test-arrow:hover{ } pre.compile_fail { - border-left: 2px solid rgba(255,0,0,.4); + border-left: 2px solid rgba(255,0,0,.5); } pre.compile_fail:hover, .information:hover + pre.compile_fail { @@ -256,7 +256,7 @@ pre.compile_fail:hover, .information:hover + pre.compile_fail { } pre.ignore { - border-left: 2px solid rgba(255,142,0,.4); + border-left: 2px solid rgba(255,142,0,.6); } pre.ignore:hover, .information:hover + pre.ignore { @@ -264,7 +264,7 @@ pre.ignore:hover, .information:hover + pre.ignore { } .tooltip.compile_fail { - color: rgba(255,0,0,.3); + color: rgba(255,0,0,.5); } .information > .compile_fail:hover { @@ -272,11 +272,11 @@ pre.ignore:hover, .information:hover + pre.ignore { } .tooltip.ignore { - color: rgba(255,142,0,.3); + color: rgba(255,142,0,.6); } .information > .ignore:hover { - color: rgba(255,142,0,1); + color: #ff9200; } .search-failed a { @@ -284,7 +284,7 @@ pre.ignore:hover, .information:hover + pre.ignore { } .tooltip .tooltiptext { - background-color: black; + background-color: #000; color: #fff; } @@ -292,12 +292,6 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: transparent black transparent transparent; } -.important-traits .tooltip .tooltiptext { - background-color: white; - color: black; - border-color: black; -} - #titles > div:not(.selected) { background-color: #e6e6e6; border-top-color: #e6e6e6; @@ -311,33 +305,6 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #888; } -.modal { - background-color: rgba(0,0,0,0.3); -} - -.modal-content { - background-color: #eee; - border-color: #999; -} - -.modal-content > .close { - background-color: #eee; - border-color: #999; -} - -.modal-content > .close:hover { - background-color: #ff1f1f; - color: white; -} - -.modal-content > .whiter { - background-color: #eee; -} - -.modal-content > .close:hover + .whiter { - background-color: #ff1f1f; -} - @media (max-width: 700px) { .sidebar-menu { background-color: #F1F1F1; diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 9fc1d76185f..6790f3bd5d0 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -8,106 +8,106 @@ //! directly written to a `Write` handle. /// The file contents of the main `rustdoc.css` file, responsible for the core layout of the page. -pub static RUSTDOC_CSS: &'static str = include_str!("static/rustdoc.css"); +pub static RUSTDOC_CSS: &str = include_str!("static/rustdoc.css"); /// The file contents of `settings.css`, responsible for the items on the settings page. -pub static SETTINGS_CSS: &'static str = include_str!("static/settings.css"); +pub static SETTINGS_CSS: &str = include_str!("static/settings.css"); /// The file contents of the `noscript.css` file, used in case JS isn't supported or is disabled. -pub static NOSCRIPT_CSS: &'static str = include_str!("static/noscript.css"); +pub static NOSCRIPT_CSS: &str = include_str!("static/noscript.css"); /// The file contents of `normalize.css`, included to even out standard elements between browser /// implementations. -pub static NORMALIZE_CSS: &'static str = include_str!("static/normalize.css"); +pub static NORMALIZE_CSS: &str = include_str!("static/normalize.css"); /// The file contents of `main.js`, which contains the core JavaScript used on documentation pages, /// including search behavior and docblock folding, among others. -pub static MAIN_JS: &'static str = include_str!("static/main.js"); +pub static MAIN_JS: &str = include_str!("static/main.js"); /// The file contents of `settings.js`, which contains the JavaScript used to handle the settings /// page. -pub static SETTINGS_JS: &'static str = include_str!("static/settings.js"); +pub static SETTINGS_JS: &str = include_str!("static/settings.js"); /// The file contents of `storage.js`, which contains functionality related to browser Local /// Storage, used to store documentation settings. -pub static STORAGE_JS: &'static str = include_str!("static/storage.js"); +pub static STORAGE_JS: &str = include_str!("static/storage.js"); /// The file contents of `brush.svg`, the icon used for the theme-switch button. -pub static BRUSH_SVG: &'static [u8] = include_bytes!("static/brush.svg"); +pub static BRUSH_SVG: &[u8] = include_bytes!("static/brush.svg"); /// The file contents of `wheel.svg`, the icon used for the settings button. -pub static WHEEL_SVG: &'static [u8] = include_bytes!("static/wheel.svg"); +pub static WHEEL_SVG: &[u8] = include_bytes!("static/wheel.svg"); /// The file contents of `down-arrow.svg`, the icon used for the crate choice combobox. -pub static DOWN_ARROW_SVG: &'static [u8] = include_bytes!("static/down-arrow.svg"); +pub static DOWN_ARROW_SVG: &[u8] = include_bytes!("static/down-arrow.svg"); /// The contents of `COPYRIGHT.txt`, the license listing for files distributed with documentation /// output. -pub static COPYRIGHT: &'static [u8] = include_bytes!("static/COPYRIGHT.txt"); +pub static COPYRIGHT: &[u8] = include_bytes!("static/COPYRIGHT.txt"); /// The contents of `LICENSE-APACHE.txt`, the text of the Apache License, version 2.0. -pub static LICENSE_APACHE: &'static [u8] = include_bytes!("static/LICENSE-APACHE.txt"); +pub static LICENSE_APACHE: &[u8] = include_bytes!("static/LICENSE-APACHE.txt"); /// The contents of `LICENSE-MIT.txt`, the text of the MIT License. -pub static LICENSE_MIT: &'static [u8] = include_bytes!("static/LICENSE-MIT.txt"); +pub static LICENSE_MIT: &[u8] = include_bytes!("static/LICENSE-MIT.txt"); /// The contents of `rust-logo.png`, the default icon of the documentation. -pub static RUST_LOGO: &'static [u8] = include_bytes!("static/rust-logo.png"); +pub static RUST_LOGO: &[u8] = include_bytes!("static/rust-logo.png"); /// The contents of `favicon.ico`, the default favicon of the documentation. -pub static RUST_FAVICON: &'static [u8] = include_bytes!("static/favicon.ico"); +pub static RUST_FAVICON: &[u8] = include_bytes!("static/favicon.ico"); /// The built-in themes given to every documentation site. pub mod themes { /// The "light" theme, selected by default when no setting is available. Used as the basis for /// the `--check-theme` functionality. - pub static LIGHT: &'static str = include_str!("static/themes/light.css"); + pub static LIGHT: &str = include_str!("static/themes/light.css"); /// The "dark" theme. - pub static DARK: &'static str = include_str!("static/themes/dark.css"); + pub static DARK: &str = include_str!("static/themes/dark.css"); } /// Files related to the Fira Sans font. pub mod fira_sans { /// The file `FiraSans-Regular.woff`, the Regular variant of the Fira Sans font. - pub static REGULAR: &'static [u8] = include_bytes!("static/FiraSans-Regular.woff"); + pub static REGULAR: &[u8] = include_bytes!("static/FiraSans-Regular.woff"); /// The file `FiraSans-Medium.woff`, the Medium variant of the Fira Sans font. - pub static MEDIUM: &'static [u8] = include_bytes!("static/FiraSans-Medium.woff"); + pub static MEDIUM: &[u8] = include_bytes!("static/FiraSans-Medium.woff"); /// The file `FiraSans-LICENSE.txt`, the license text for the Fira Sans font. - pub static LICENSE: &'static [u8] = include_bytes!("static/FiraSans-LICENSE.txt"); + pub static LICENSE: &[u8] = include_bytes!("static/FiraSans-LICENSE.txt"); } /// Files related to the Source Serif Pro font. pub mod source_serif_pro { /// The file `SourceSerifPro-Regular.ttf.woff`, the Regular variant of the Source Serif Pro /// font. - pub static REGULAR: &'static [u8] = include_bytes!("static/SourceSerifPro-Regular.ttf.woff"); + pub static REGULAR: &[u8] = include_bytes!("static/SourceSerifPro-Regular.ttf.woff"); /// The file `SourceSerifPro-Bold.ttf.woff`, the Bold variant of the Source Serif Pro font. - pub static BOLD: &'static [u8] = include_bytes!("static/SourceSerifPro-Bold.ttf.woff"); + pub static BOLD: &[u8] = include_bytes!("static/SourceSerifPro-Bold.ttf.woff"); /// The file `SourceSerifPro-It.ttf.woff`, the Italic variant of the Source Serif Pro font. - pub static ITALIC: &'static [u8] = include_bytes!("static/SourceSerifPro-It.ttf.woff"); + pub static ITALIC: &[u8] = include_bytes!("static/SourceSerifPro-It.ttf.woff"); /// The file `SourceSerifPro-LICENSE.txt`, the license text for the Source Serif Pro font. - pub static LICENSE: &'static [u8] = include_bytes!("static/SourceSerifPro-LICENSE.md"); + pub static LICENSE: &[u8] = include_bytes!("static/SourceSerifPro-LICENSE.md"); } /// Files related to the Source Code Pro font. pub mod source_code_pro { /// The file `SourceCodePro-Regular.woff`, the Regular variant of the Source Code Pro font. - pub static REGULAR: &'static [u8] = include_bytes!("static/SourceCodePro-Regular.woff"); + pub static REGULAR: &[u8] = include_bytes!("static/SourceCodePro-Regular.woff"); /// The file `SourceCodePro-Semibold.woff`, the Semibold variant of the Source Code Pro font. - pub static SEMIBOLD: &'static [u8] = include_bytes!("static/SourceCodePro-Semibold.woff"); + pub static SEMIBOLD: &[u8] = include_bytes!("static/SourceCodePro-Semibold.woff"); /// The file `SourceCodePro-LICENSE.txt`, the license text of the Source Code Pro font. - pub static LICENSE: &'static [u8] = include_bytes!("static/SourceCodePro-LICENSE.txt"); + pub static LICENSE: &[u8] = include_bytes!("static/SourceCodePro-LICENSE.txt"); } /// Files related to the sidebar in rustdoc sources. pub mod sidebar { /// File script to handle sidebar. - pub static SOURCE_SCRIPT: &'static str = include_str!("static/source-script.js"); + pub static SOURCE_SCRIPT: &str = include_str!("static/source-script.js"); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 4e0a2d94274..3c1f0509bba 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -17,6 +17,7 @@ extern crate env_logger; extern crate getopts; extern crate rustc; +extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; extern crate rustc_data_structures; @@ -26,6 +27,7 @@ extern crate rustc_expand; extern crate rustc_feature; extern crate rustc_hir; extern crate rustc_index; +extern crate rustc_infer; extern crate rustc_interface; extern crate rustc_lexer; extern crate rustc_lint; @@ -36,8 +38,8 @@ extern crate rustc_resolve; extern crate rustc_session; extern crate rustc_span as rustc_span; extern crate rustc_target; +extern crate rustc_trait_selection; extern crate rustc_typeck; -extern crate syntax; extern crate test as testing; #[macro_use] extern crate log; @@ -47,8 +49,8 @@ use std::env; use std::panic; use std::process; -use rustc::session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; -use rustc::session::{early_error, early_warn}; +use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; +use rustc_session::{early_error, early_warn}; #[macro_use] mod externalfiles; diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index a37efc22c93..a41fdd2ff17 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -19,7 +19,7 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { let mut count = 0; for line in s.lines() { - if line.starts_with("# ") || line.starts_with("%") { + if line.starts_with("# ") || line.starts_with('%') { // trim the whitespace after the symbol metadata.push(line[1..].trim_start()); count += line.len() + 1; diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 7ed531c9206..f48224512ba 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -1,11 +1,14 @@ use crate::clean; +use crate::config::OutputFormat; use crate::core::DocContext; use crate::fold::{self, DocFolder}; use crate::passes::Pass; +use rustc_ast::attr; use rustc_span::symbol::sym; use rustc_span::FileName; -use syntax::attr; +use serde::Serialize; +use serde_json; use std::collections::BTreeMap; use std::ops; @@ -16,16 +19,16 @@ pub const CALCULATE_DOC_COVERAGE: Pass = Pass { description: "counts the number of items with and without documentation", }; -fn calculate_doc_coverage(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { - let mut calc = CoverageCalculator::default(); +fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::Crate { + let mut calc = CoverageCalculator::new(); let krate = calc.fold_crate(krate); - calc.print_results(); + calc.print_results(ctx.renderinfo.borrow().output_format); krate } -#[derive(Default, Copy, Clone)] +#[derive(Default, Copy, Clone, Serialize)] struct ItemCount { total: u64, with_docs: u64, @@ -64,13 +67,41 @@ impl ops::AddAssign for ItemCount { } } -#[derive(Default)] struct CoverageCalculator { items: BTreeMap, } +fn limit_filename_len(filename: String) -> String { + let nb_chars = filename.chars().count(); + if nb_chars > 35 { + "...".to_string() + + &filename[filename.char_indices().nth(nb_chars - 32).map(|x| x.0).unwrap_or(0)..] + } else { + filename + } +} + impl CoverageCalculator { - fn print_results(&self) { + fn new() -> CoverageCalculator { + CoverageCalculator { items: Default::default() } + } + + fn to_json(&self) -> String { + serde_json::to_string( + &self + .items + .iter() + .map(|(k, v)| (k.to_string(), v)) + .collect::>(), + ) + .expect("failed to convert JSON data to string") + } + + fn print_results(&self, output_format: Option) { + if output_format.map(|o| o.is_json()).unwrap_or_else(|| false) { + println!("{}", self.to_json()); + return; + } let mut total = ItemCount::default(); fn print_table_line() { @@ -93,15 +124,7 @@ impl CoverageCalculator { for (file, &count) in &self.items { if let Some(percentage) = count.percentage() { - let mut name = file.to_string(); - // if a filename is too long, shorten it so we don't blow out the table - // FIXME(misdreavus): this needs to count graphemes, and probably also track - // double-wide characters... - if name.len() > 35 { - name = "...".to_string() + &name[name.len() - 32..]; - } - - print_table_record(&name, count, percentage); + print_table_record(&limit_filename_len(file.to_string()), count, percentage); total += count; } diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 3b7c0db05a5..3e0ff0b3d9a 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,10 +1,10 @@ +use rustc_ast::token; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler}; use rustc_parse::lexer::StringReader as Lexer; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{FileName, InnerSpan}; -use syntax::token; use crate::clean; use crate::core::DocContext; @@ -32,9 +32,9 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { let emitter = BufferEmitter { messages: Lrc::clone(&buffered_messages) }; - let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let handler = Handler::with_emitter(false, None, Box::new(emitter)); - let sess = ParseSess::with_span_handler(handler, cm); + let sess = ParseSess::with_span_handler(handler, sm); let source_file = sess.source_map().new_source_file( FileName::Custom(String::from("doctest")), dox[code_block.code].to_owned(), diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 79bcfe7aee7..113c781e332 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1,5 +1,5 @@ -use rustc::lint; use rustc::ty; +use rustc_ast::ast::{self, Ident}; use rustc_errors::Applicability; use rustc_expand::base::SyntaxExtensionKind; use rustc_feature::UnstableFeatures; @@ -11,9 +11,9 @@ use rustc_hir::def::{ }; use rustc_hir::def_id::DefId; use rustc_resolve::ParentScope; +use rustc_session::lint; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; -use syntax::ast::{self, Ident}; use std::ops::Range; @@ -60,7 +60,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { &self, path_str: &str, current_item: &Option, - module_id: syntax::ast::NodeId, + module_id: rustc_ast::ast::NodeId, ) -> Result<(Res, Option), ErrorKind> { let cx = self.cx; @@ -95,7 +95,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .tcx .inherent_impls(did) .iter() - .flat_map(|imp| cx.tcx.associated_items(*imp)) + .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order()) .any(|item| item.ident.name == variant_name) { return Err(ErrorKind::ResolutionFailure); @@ -149,7 +149,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // In case this is a trait item, skip the // early return and try looking for the trait. let value = match res { - Res::Def(DefKind::Method, _) | Res::Def(DefKind::AssocConst, _) => true, + Res::Def(DefKind::AssocFn, _) | Res::Def(DefKind::AssocConst, _) => true, Res::Def(DefKind::AssocTy, _) => false, Res::Def(DefKind::Variant, _) => { return handle_variant(cx, res, extra_fragment); @@ -206,8 +206,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { return cx .tcx .associated_items(did) - .iter() - .find(|item| item.ident.name == item_name) + .filter_by_name_unhygienic(item_name) + .next() .and_then(|item| match item.kind { ty::AssocKind::Method => Some("method"), _ => None, @@ -234,7 +234,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .tcx .inherent_impls(did) .iter() - .flat_map(|imp| cx.tcx.associated_items(*imp)) + .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order()) .find(|item| item.ident.name == item_name); if let Some(item) = item { let out = match item.kind { @@ -348,7 +348,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let parent_node = self.cx.as_local_hir_id(item.def_id).and_then(|hir_id| { // FIXME: this fails hard for impls in non-module scope, but is necessary for the // current `resolve()` implementation. - match self.cx.tcx.hir().get_module_parent_node(hir_id) { + match self.cx.as_local_hir_id(self.cx.tcx.parent_module(hir_id).to_def_id()).unwrap() { id if id != hir_id => Some(id), _ => None, } @@ -813,7 +813,7 @@ fn ambiguity_error( for (res, ns) in candidates { let (action, mut suggestion) = match res { - Res::Def(DefKind::Method, _) | Res::Def(DefKind::Fn, _) => { + Res::Def(DefKind::AssocFn, _) | Res::Def(DefKind::Fn, _) => { ("add parentheses", format!("{}()", path_str)) } Res::Def(DefKind::Macro(..), _) => { @@ -896,20 +896,20 @@ fn handle_variant( } const PRIMITIVES: &[(&str, Res)] = &[ - ("u8", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U8))), - ("u16", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U16))), - ("u32", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U32))), - ("u64", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U64))), - ("u128", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::U128))), - ("usize", Res::PrimTy(hir::PrimTy::Uint(syntax::ast::UintTy::Usize))), - ("i8", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I8))), - ("i16", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I16))), - ("i32", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I32))), - ("i64", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I64))), - ("i128", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::I128))), - ("isize", Res::PrimTy(hir::PrimTy::Int(syntax::ast::IntTy::Isize))), - ("f32", Res::PrimTy(hir::PrimTy::Float(syntax::ast::FloatTy::F32))), - ("f64", Res::PrimTy(hir::PrimTy::Float(syntax::ast::FloatTy::F64))), + ("u8", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::ast::UintTy::U8))), + ("u16", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::ast::UintTy::U16))), + ("u32", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::ast::UintTy::U32))), + ("u64", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::ast::UintTy::U64))), + ("u128", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::ast::UintTy::U128))), + ("usize", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::ast::UintTy::Usize))), + ("i8", Res::PrimTy(hir::PrimTy::Int(rustc_ast::ast::IntTy::I8))), + ("i16", Res::PrimTy(hir::PrimTy::Int(rustc_ast::ast::IntTy::I16))), + ("i32", Res::PrimTy(hir::PrimTy::Int(rustc_ast::ast::IntTy::I32))), + ("i64", Res::PrimTy(hir::PrimTy::Int(rustc_ast::ast::IntTy::I64))), + ("i128", Res::PrimTy(hir::PrimTy::Int(rustc_ast::ast::IntTy::I128))), + ("isize", Res::PrimTy(hir::PrimTy::Int(rustc_ast::ast::IntTy::Isize))), + ("f32", Res::PrimTy(hir::PrimTy::Float(rustc_ast::ast::FloatTy::F32))), + ("f64", Res::PrimTy(hir::PrimTy::Float(rustc_ast::ast::FloatTy::F64))), ("str", Res::PrimTy(hir::PrimTy::Str)), ("bool", Res::PrimTy(hir::PrimTy::Bool)), ("char", Res::PrimTy(hir::PrimTy::Char)), diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 9e48904a47d..38f371783e9 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -1,9 +1,9 @@ //! Contains information about "passes", used to modify crate information during the documentation //! process. -use rustc::lint; use rustc::middle::privacy::AccessLevels; use rustc_hir::def_id::{DefId, DefIdSet}; +use rustc_session::lint; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use std::mem; use std::ops::Range; @@ -340,12 +340,12 @@ pub fn look_for_tests<'tcx>( find_testable_code(&dox, &mut tests, ErrorCodes::No, false); - if check_missing_code == true && tests.found_tests == 0 { + if check_missing_code && tests.found_tests == 0 { let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); cx.tcx.struct_span_lint_hir(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id, sp, |lint| { lint.build("missing code example in this documentation").emit() }); - } else if check_missing_code == false + } else if !check_missing_code && tests.found_tests > 0 && !cx.renderinfo.borrow().access_levels.is_public(item.def_id) { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 0c7dfa1417a..c5aa4677d56 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -1,11 +1,13 @@ use rustc::hir::map::Map; -use rustc::session::{self, config, DiagnosticOutput}; use rustc::util::common::ErrorReported; +use rustc_ast::ast; +use rustc_ast::with_globals; use rustc_data_structures::sync::Lrc; use rustc_feature::UnstableFeatures; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_interface::interface; +use rustc_session::{self, config, DiagnosticOutput, Session}; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMap; use rustc_span::symbol::sym; @@ -17,8 +19,6 @@ use std::panic; use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::str; -use syntax::ast; -use syntax::with_globals; use tempfile::Builder as TempFileBuilder; use crate::clean::Attributes; @@ -52,7 +52,7 @@ pub fn run(options: Options) -> i32 { cg: options.codegen_options.clone(), externs: options.externs.clone(), unstable_features: UnstableFeatures::from_environment(), - lint_cap: Some(::rustc::lint::Level::Allow), + lint_cap: Some(rustc_session::lint::Level::Allow), actually_rustdoc: true, debugging_opts: config::DebuggingOptions { ..config::basic_debugging_options() }, edition: options.edition, @@ -107,12 +107,12 @@ pub fn run(options: Options) -> i32 { let mut hir_collector = HirCollector { sess: compiler.session(), collector: &mut collector, - map: *tcx.hir(), + map: tcx.hir(), codes: ErrorCodes::from( compiler.session().opts.unstable_features.is_nightly_build(), ), }; - hir_collector.visit_testable("".to_string(), &krate.attrs, |this| { + hir_collector.visit_testable("".to_string(), &krate.item.attrs, |this| { intravisit::walk_crate(this, krate); }); }); @@ -146,6 +146,7 @@ fn scrape_test_config(krate: &::rustc_hir::Crate) -> TestOptions { TestOptions { no_crate_inject: false, display_warnings: false, attrs: Vec::new() }; let test_attrs: Vec<_> = krate + .item .attrs .iter() .filter(|a| a.check_name(sym::doc)) @@ -387,7 +388,7 @@ pub fn make_test( prog.push_str(&crate_attrs); prog.push_str(&crates); - // Uses libsyntax to parse the doctest and find if there's a main fn and the extern + // Uses librustc_ast to parse the doctest and find if there's a main fn and the extern // crate already is included. let result = rustc_driver::catch_fatal_errors(|| { with_globals(edition, || { @@ -398,16 +399,16 @@ pub fn make_test( use rustc_span::source_map::FilePathMapping; let filename = FileName::anon_source_code(s); - let source = crates + &everything_else; + let source = crates + everything_else; // Any errors in parsing should also appear when the doctest is compiled for real, so just - // send all the errors that libsyntax emits directly into a `Sink` instead of stderr. - let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr. + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(false, None, box emitter); - let sess = ParseSess::with_span_handler(handler, cm); + let sess = ParseSess::with_span_handler(handler, sm); let mut found_main = false; let mut found_extern_crate = cratename.is_none(); @@ -449,7 +450,7 @@ pub fn make_test( } if !found_macro { - if let ast::ItemKind::Mac(..) = item.kind { + if let ast::ItemKind::MacCall(..) = item.kind { found_macro = true; } } @@ -853,9 +854,9 @@ impl Tester for Collector { } struct HirCollector<'a, 'hir> { - sess: &'a session::Session, + sess: &'a Session, collector: &'a mut Collector, - map: &'a Map<'hir>, + map: Map<'hir>, codes: ErrorCodes, } @@ -903,8 +904,8 @@ impl<'a, 'hir> HirCollector<'a, 'hir> { impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> { type Map = Map<'hir>; - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> { - intravisit::NestedVisitorMap::All(&self.map) + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::All(self.map) } fn visit_item(&mut self, item: &'hir hir::Item) { @@ -955,7 +956,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> { } fn visit_macro_def(&mut self, macro_def: &'hir hir::MacroDef) { - self.visit_testable(macro_def.name.to_string(), ¯o_def.attrs, |_| ()); + self.visit_testable(macro_def.ident.to_string(), ¯o_def.attrs, |_| ()); } } diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs index eb8eabe1c03..a8a571e7c54 100644 --- a/src/librustdoc/theme.rs +++ b/src/librustdoc/theme.rs @@ -191,7 +191,7 @@ fn build_rule(v: &[u8], positions: &[usize]) -> String { .replace("{", "") .replace("}", "") .split(' ') - .filter(|s| s.len() > 0) + .filter(|s| !s.is_empty()) .collect::>() .join(" "), ) @@ -253,9 +253,9 @@ pub fn get_differences(against: &CssPath, other: &CssPath, v: &mut Vec) break; } } - if found == false { + if !found { v.push(format!(" Missing \"{}\" rule", child.name)); - } else if found_working == false { + } else if !found_working { v.extend(tmp.iter().cloned()); } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d3d45ccccad..feaf391c95a 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -3,6 +3,7 @@ use rustc::middle::privacy::AccessLevel; use rustc::ty::TyCtxt; +use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -12,7 +13,6 @@ use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym}; use rustc_span::{self, Span}; -use syntax::ast; use std::mem; @@ -64,11 +64,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub fn visit(mut self, krate: &'tcx hir::Crate) -> Module<'tcx> { let mut module = self.visit_mod_contents( - krate.span, - krate.attrs, + krate.item.span, + krate.item.attrs, &Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public }, hir::CRATE_HIR_ID, - &krate.module, + &krate.item.module, None, ); // Attach the crate's exported macros to the top-level module: @@ -620,8 +620,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { def: &'tcx hir::MacroDef, renamed: Option, ) -> Macro<'tcx> { - debug!("visit_local_macro: {}", def.name); - let tts = def.body.trees().collect::>(); + debug!("visit_local_macro: {}", def.ident); + let tts = def.ast.body.inner_tokens().trees().collect::>(); // Extract the spans of all matchers. They represent the "interface" of the macro. let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect(); @@ -629,7 +629,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hid: def.hir_id, def_id: self.cx.tcx.hir().local_def_id(def.hir_id), attrs: &def.attrs, - name: renamed.unwrap_or(def.name), + name: renamed.unwrap_or(def.ident.name), whence: def.span, matchers, imported_from: None, diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 19283ffc438..8c6548cd3c5 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -36,6 +36,7 @@ pub trait Encoder { fn emit_str(&mut self, v: &str) -> Result<(), Self::Error>; // Compound types: + #[inline] fn emit_enum(&mut self, _name: &str, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, @@ -57,6 +58,7 @@ pub trait Encoder { f(self) } + #[inline] fn emit_enum_variant_arg(&mut self, _a_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, @@ -89,6 +91,7 @@ pub trait Encoder { self.emit_enum_variant_arg(f_idx, f) } + #[inline] fn emit_struct(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, @@ -96,6 +99,7 @@ pub trait Encoder { f(self) } + #[inline] fn emit_struct_field( &mut self, _f_name: &str, @@ -108,6 +112,7 @@ pub trait Encoder { f(self) } + #[inline] fn emit_tuple(&mut self, _len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, @@ -115,6 +120,7 @@ pub trait Encoder { f(self) } + #[inline] fn emit_tuple_arg(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, @@ -164,6 +170,7 @@ pub trait Encoder { f(self) } + #[inline] fn emit_seq_elt(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, @@ -179,6 +186,7 @@ pub trait Encoder { f(self) } + #[inline] fn emit_map_elt_key(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, @@ -186,6 +194,7 @@ pub trait Encoder { f(self) } + #[inline] fn emit_map_elt_val(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error>, @@ -218,6 +227,7 @@ pub trait Decoder { fn read_str(&mut self) -> Result, Self::Error>; // Compound types: + #[inline] fn read_enum(&mut self, _name: &str, f: F) -> Result where F: FnOnce(&mut Self) -> Result, @@ -225,6 +235,7 @@ pub trait Decoder { f(self) } + #[inline] fn read_enum_variant(&mut self, _names: &[&str], mut f: F) -> Result where F: FnMut(&mut Self, usize) -> Result, @@ -233,6 +244,7 @@ pub trait Decoder { f(self, disr) } + #[inline] fn read_enum_variant_arg(&mut self, _a_idx: usize, f: F) -> Result where F: FnOnce(&mut Self) -> Result, @@ -259,6 +271,7 @@ pub trait Decoder { self.read_enum_variant_arg(f_idx, f) } + #[inline] fn read_struct(&mut self, _s_name: &str, _len: usize, f: F) -> Result where F: FnOnce(&mut Self) -> Result, @@ -266,6 +279,7 @@ pub trait Decoder { f(self) } + #[inline] fn read_struct_field( &mut self, _f_name: &str, @@ -278,6 +292,7 @@ pub trait Decoder { f(self) } + #[inline] fn read_tuple(&mut self, _len: usize, f: F) -> Result where F: FnOnce(&mut Self) -> Result, @@ -285,6 +300,7 @@ pub trait Decoder { f(self) } + #[inline] fn read_tuple_arg(&mut self, _a_idx: usize, f: F) -> Result where F: FnOnce(&mut Self) -> Result, @@ -328,6 +344,7 @@ pub trait Decoder { f(self, len) } + #[inline] fn read_seq_elt(&mut self, _idx: usize, f: F) -> Result where F: FnOnce(&mut Self) -> Result, @@ -343,6 +360,7 @@ pub trait Decoder { f(self, len) } + #[inline] fn read_map_elt_key(&mut self, _idx: usize, f: F) -> Result where F: FnOnce(&mut Self) -> Result, @@ -350,6 +368,7 @@ pub trait Decoder { f(self) } + #[inline] fn read_map_elt_val(&mut self, _idx: usize, f: F) -> Result where F: FnOnce(&mut Self) -> Result, diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 8965c6860c4..25f3ddcbeba 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -133,22 +133,41 @@ pub use alloc_crate::alloc::*; #[derive(Debug, Default, Copy, Clone)] pub struct System; -// The AllocRef impl just forwards to the GlobalAlloc impl, which is in `std::sys::*::alloc`. +// The AllocRef impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl, +// which is in `std::sys::*::alloc`. #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl AllocRef for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) + fn alloc(&mut self, layout: Layout) -> Result<(NonNull, usize), AllocErr> { + if layout.size() == 0 { + Ok((layout.dangling(), 0)) + } else { + unsafe { + NonNull::new(GlobalAlloc::alloc(self, layout)) + .ok_or(AllocErr) + .map(|p| (p, layout.size())) + } + } } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) + fn alloc_zeroed(&mut self, layout: Layout) -> Result<(NonNull, usize), AllocErr> { + if layout.size() == 0 { + Ok((layout.dangling(), 0)) + } else { + unsafe { + NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)) + .ok_or(AllocErr) + .map(|p| (p, layout.size())) + } + } } #[inline] unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) + if layout.size() != 0 { + GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) + } } #[inline] @@ -157,8 +176,18 @@ unsafe impl AllocRef for System { ptr: NonNull, layout: Layout, new_size: usize, - ) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) + ) -> Result<(NonNull, usize), AllocErr> { + match (layout.size(), new_size) { + (0, 0) => Ok((layout.dangling(), 0)), + (0, _) => self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())), + (_, 0) => { + self.dealloc(ptr, layout); + Ok((layout.dangling(), 0)) + } + (_, _) => NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)) + .ok_or(AllocErr) + .map(|p| (p, new_size)), + } } } diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs index a1c9aa75d77..34317c7a2ee 100644 --- a/src/libstd/backtrace.rs +++ b/src/libstd/backtrace.rs @@ -92,6 +92,7 @@ // a backtrace or actually symbolizing it. use crate::env; +use crate::ffi::c_void; use crate::fmt; use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use crate::sync::Mutex; @@ -144,10 +145,16 @@ fn _assert_send_sync() { } struct BacktraceFrame { - frame: backtrace::Frame, + frame: RawFrame, symbols: Vec, } +enum RawFrame { + Actual(backtrace::Frame), + #[cfg(test)] + Fake, +} + struct BacktraceSymbol { name: Option>, filename: Option, @@ -162,8 +169,8 @@ enum BytesOrWide { impl fmt::Debug for Backtrace { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut capture = match &self.inner { - Inner::Unsupported => return fmt.write_str("unsupported backtrace"), - Inner::Disabled => return fmt.write_str("disabled backtrace"), + Inner::Unsupported => return fmt.write_str(""), + Inner::Disabled => return fmt.write_str(""), Inner::Captured(c) => c.lock().unwrap(), }; capture.resolve(); @@ -193,11 +200,11 @@ impl fmt::Debug for BacktraceSymbol { if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) { write!(fmt, "fn: \"{:#}\"", fn_name)?; } else { - write!(fmt, "fn: \"\"")?; + write!(fmt, "fn: ")?; } if let Some(fname) = self.filename.as_ref() { - write!(fmt, ", file: {:?}", fname)?; + write!(fmt, ", file: \"{:?}\"", fname)?; } if let Some(line) = self.lineno.as_ref() { @@ -293,7 +300,10 @@ impl Backtrace { let mut actual_start = None; unsafe { backtrace::trace_unsynchronized(|frame| { - frames.push(BacktraceFrame { frame: frame.clone(), symbols: Vec::new() }); + frames.push(BacktraceFrame { + frame: RawFrame::Actual(frame.clone()), + symbols: Vec::new(), + }); if frame.symbol_address() as usize == ip && actual_start.is_none() { actual_start = Some(frames.len()); } @@ -304,7 +314,7 @@ impl Backtrace { // If no frames came out assume that this is an unsupported platform // since `backtrace` doesn't provide a way of learning this right now, // and this should be a good enough approximation. - let inner = if frames.len() == 0 { + let inner = if frames.is_empty() { Inner::Unsupported } else { Inner::Captured(Mutex::new(Capture { @@ -393,8 +403,13 @@ impl Capture { let _lock = lock(); for frame in self.frames.iter_mut() { let symbols = &mut frame.symbols; + let frame = match &frame.frame { + RawFrame::Actual(frame) => frame, + #[cfg(test)] + RawFrame::Fake => unimplemented!(), + }; unsafe { - backtrace::resolve_frame_unsynchronized(&frame.frame, |symbol| { + backtrace::resolve_frame_unsynchronized(frame, |symbol| { symbols.push(BacktraceSymbol { name: symbol.name().map(|m| m.as_bytes().to_vec()), filename: symbol.filename_raw().map(|b| match b { @@ -408,3 +423,65 @@ impl Capture { } } } + +impl RawFrame { + fn ip(&self) -> *mut c_void { + match self { + RawFrame::Actual(frame) => frame.ip(), + #[cfg(test)] + RawFrame::Fake => 1 as *mut c_void, + } + } +} + +#[test] +fn test_debug() { + let backtrace = Backtrace { + inner: Inner::Captured(Mutex::new(Capture { + actual_start: 1, + resolved: true, + frames: vec![ + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![BacktraceSymbol { + name: Some(b"std::backtrace::Backtrace::create".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())), + lineno: Some(100), + }], + }, + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![BacktraceSymbol { + name: Some(b"__rust_maybe_catch_panic".to_vec()), + filename: None, + lineno: None, + }], + }, + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![ + BacktraceSymbol { + name: Some(b"std::rt::lang_start_internal".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), + lineno: Some(300), + }, + BacktraceSymbol { + name: Some(b"std::rt::lang_start".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), + lineno: Some(400), + }, + ], + }, + ], + })), + }; + + #[rustfmt::skip] + let expected = "Backtrace [\ + \n { fn: \"__rust_maybe_catch_panic\" },\ + \n { fn: \"std::rt::lang_start_internal\", file: \"rust/rt.rs\", line: 300 },\ + \n { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\ + \n]"; + + assert_eq!(format!("{:#?}", backtrace), expected); +} diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index d0e1a01b006..44f8e8bd171 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2461,7 +2461,7 @@ impl RandomState { KEYS.with(|keys| { let (k0, k1) = keys.get(); keys.set((k0.wrapping_add(1), k1)); - RandomState { k0: k0, k1: k1 } + RandomState { k0, k1 } }) } } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index b480581e21b..2a370f19296 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -135,7 +135,7 @@ pub trait Error: Debug + Display { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.41.0", reason = "use the Display impl or to_string()")] + #[rustc_deprecated(since = "1.42.0", reason = "use the Display impl or to_string()")] fn description(&self) -> &str { "description() is deprecated; use Display" } @@ -552,6 +552,9 @@ impl Error for char::ParseCharError { } } +#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] +impl Error for alloc::collections::TryReserveError {} + // Copied from `any.rs`. impl dyn Error + 'static { /// Returns `true` if the boxed type is the same as `T` diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 941ea6a767c..20425aea8d5 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -4,6 +4,9 @@ //! *[See also the `f32` primitive type](../../std/primitive.f32.html).* //! //! Mathematically significant numbers are provided in the `consts` sub-module. +//! +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index d89b38e1a00..a1128a589a6 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -4,6 +4,9 @@ //! *[See also the `f64` primitive type](../../std/primitive.f64.html).* //! //! Mathematically significant numbers are provided in the `consts` sub-module. +//! +//! Although using these constants won’t cause compilation warnings, +//! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 700e015b08e..04eaba515ff 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -6,6 +6,7 @@ use crate::fmt::{self, Write}; use crate::io; use crate::mem; use crate::memchr; +use crate::num::NonZeroU8; use crate::ops; use crate::os::raw::c_char; use crate::ptr; @@ -741,6 +742,32 @@ impl From> for CString { } } +#[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")] +impl From> for CString { + /// Converts a [`Vec`]`<`[`NonZeroU8`]`>` into a [`CString`] without + /// copying nor checking for inner null bytes. + /// + /// [`CString`]: ../ffi/struct.CString.html + /// [`NonZeroU8`]: ../num/struct.NonZeroU8.html + /// [`Vec`]: ../vec/struct.Vec.html + #[inline] + fn from(v: Vec) -> CString { + unsafe { + // Transmute `Vec` to `Vec`. + let v: Vec = { + // Safety: + // - transmuting between `NonZeroU8` and `u8` is sound; + // - `alloc::Layout == alloc::Layout`. + let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v); + Vec::from_raw_parts(ptr.cast::(), len, cap) + }; + // Safety: `v` cannot contain null bytes, given the type-level + // invariant of `NonZeroU8`. + CString::from_vec_unchecked(v) + } + } +} + #[stable(feature = "more_box_slice_clone", since = "1.29.0")] impl Clone for Box { #[inline] diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index cff7bbe5ef1..e20fcfafa22 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -407,7 +407,7 @@ impl File { /// /// It is equivalent to `OpenOptions::new()` but allows you to write more /// readable code. Instead of `OpenOptions::new().read(true).open("foo.txt")` - /// you can write `File::with_options().read(true).open("foo.txt"). This + /// you can write `File::with_options().read(true).open("foo.txt")`. This /// also avoids the need to import `OpenOptions`. /// /// See the [`OpenOptions::new`] function for more details. @@ -844,10 +844,7 @@ impl OpenOptions { self } - /// Sets the option for creating a new file. - /// - /// This option indicates whether a new file will be created if the file - /// does not yet already exist. + /// Sets the option to create a new file, or open it if it already exists. /// /// In order for the file to be created, [`write`] or [`append`] access must /// be used. @@ -868,11 +865,10 @@ impl OpenOptions { self } - /// Sets the option to always create a new file. + /// Sets the option to create a new file, failing if it already exists. /// - /// This option indicates whether a new file will be created. - /// No file is allowed to exist at the target location, also no (dangling) - /// symlink. + /// No file is allowed to exist at the target location, also no (dangling) symlink. In this + /// way, if the call succeeds, the file returned is guaranteed to be new. /// /// This option is useful because it is atomic. Otherwise between checking /// whether a file exists and creating a new one, the file may have been diff --git a/src/libstd/future.rs b/src/libstd/future.rs index f74c84e6dfd..c1ca6771326 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -16,9 +16,10 @@ pub use core::future::*; /// /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). +// This is `const` to avoid extra errors after we recover from `const async fn` #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] -pub fn from_generator>(x: T) -> impl Future { +pub const fn from_generator>(x: T) -> impl Future { GenFuture(x) } @@ -40,10 +41,7 @@ impl> Future for GenFuture { // Safe because we're !Unpin + !Drop mapping to a ?Unpin value let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; let _guard = unsafe { set_task_context(cx) }; - match gen.resume( - #[cfg(not(bootstrap))] - (), - ) { + match gen.resume(()) { GeneratorState::Yielded(()) => Poll::Pending, GeneratorState::Complete(x) => Poll::Ready(x), } diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 9787cbb556b..f36aa1846a1 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -96,7 +96,7 @@ impl Cursor { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: T) -> Cursor { - Cursor { pos: 0, inner: inner } + Cursor { pos: 0, inner } } /// Consumes this cursor, returning the underlying value. diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 67b382c7a84..dc831432c17 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -371,7 +371,7 @@ where F: FnMut(&R) -> usize, { let start_len = buf.len(); - let mut g = Guard { len: buf.len(), buf: buf }; + let mut g = Guard { len: buf.len(), buf }; let ret; loop { if g.len == g.buf.len() { @@ -497,7 +497,6 @@ where /// [`&str`]: ../../std/primitive.str.html /// [slice]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] -#[doc(spotlight)] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -939,7 +938,7 @@ pub trait Read { where Self: Sized, { - Take { inner: self, limit: limit } + Take { inner: self, limit } } } @@ -1051,6 +1050,7 @@ impl<'a> DerefMut for IoSliceMut<'a> { /// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on /// Windows. #[stable(feature = "iovec", since = "1.36.0")] +#[derive(Copy, Clone)] #[repr(transparent)] pub struct IoSlice<'a>(sys::io::IoSlice<'a>); @@ -1228,7 +1228,6 @@ impl Initializer { /// /// [`write_all`]: #method.write_all #[stable(feature = "rust1", since = "1.0.0")] -#[doc(spotlight)] pub trait Write { /// Write a buffer into this writer, returning how many bytes were written. /// @@ -2396,9 +2395,9 @@ impl Iterator for Lines { match self.buf.read_line(&mut buf) { Ok(0) => None, Ok(_n) => { - if buf.ends_with("\n") { + if buf.ends_with('\n') { buf.pop(); - if buf.ends_with("\r") { + if buf.ends_with('\r') { buf.pop(); } } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 6add644dcc2..0fb0757792e 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -302,7 +302,7 @@ impl Stdin { StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } } - /// Locks this handle and reads a line of input into the specified buffer. + /// Locks this handle and reads a line of input, appending it to the specified buffer. /// /// For detailed semantics of this method, see the documentation on /// [`BufRead::read_line`]. @@ -792,10 +792,14 @@ fn print_to( { let result = local_s .try_with(|s| { - if let Ok(mut borrowed) = s.try_borrow_mut() { - if let Some(w) = borrowed.as_mut() { - return w.write_fmt(args); - } + // Note that we completely remove a local sink to write to in case + // our printing recursively panics/prints, so the recursive + // panic/print goes to the global sink instead of our local sink. + let prev = s.borrow_mut().take(); + if let Some(mut w) = prev { + let result = w.write_fmt(args); + *s.borrow_mut() = Some(w); + return result; } global_s().write_fmt(args) }) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 58f4e76cd30..314424631fc 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -234,12 +234,55 @@ mod crate_keyword {} #[doc(keyword = "else")] // -/// What to do when an [`if`] condition does not hold. +/// What expression to evaluate when an [`if`] condition evaluates to [`false`]. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// `else` expressions are optional. When no else expressions are supplied it is assumed to evaluate +/// to the unit type `()`. +/// +/// The type that the `else` blocks evaluate to must be compatible with the type that the `if` block +/// evaluates to. +/// +/// As can be seen below, `else` must be followed by either: `if`, `if let`, or a block `{}` and it +/// will return the value of that expression. +/// +/// ```rust +/// let result = if true == false { +/// "oh no" +/// } else if "something" == "other thing" { +/// "oh dear" +/// } else if let Some(200) = "blarg".parse::().ok() { +/// "uh oh" +/// } else { +/// println!("Sneaky side effect."); +/// "phew, nothing's broken" +/// }; +/// ``` +/// +/// Here's another example but here we do not try and return an expression: +/// +/// ```rust +/// if true == false { +/// println!("oh no"); +/// } else if "something" == "other thing" { +/// println!("oh dear"); +/// } else if let Some(200) = "blarg".parse::().ok() { +/// println!("uh oh"); +/// } else { +/// println!("phew, nothing's broken"); +/// } +/// ``` +/// +/// The above is _still_ an expression but it will always evaluate to `()`. /// +/// There is possibly no limit to the number of `else` blocks that could follow an `if` expression +/// however if you have several then a [`match`] expression might be preferable. +/// +/// Read more about control flow in the [Rust Book]. +/// +/// [Rust Book]: ../book/ch03-05-control-flow.html#handling-multiple-conditions-with-else-if +/// [`match`]: keyword.match.html +/// [`false`]: keyword.false.html /// [`if`]: keyword.if.html -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 mod else_keyword {} #[doc(keyword = "enum")] @@ -637,10 +680,18 @@ mod impl_keyword {} // /// Iterate over a series of values with [`for`]. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// The expression immediately following `in` must implement the [`Iterator`] trait. +/// +/// ## Literal Examples: +/// +/// * `for _ **in** 1..3 {}` - Iterate over an exclusive range up to but excluding 3. +/// * `for _ **in** 1..=3 {}` - Iterate over an inclusive range up to and includeing 3. +/// +/// (Read more about [range patterns]) /// +/// [`Iterator`]: ../book/ch13-04-performance.html +/// [`range patterns`]: ../reference/patterns.html?highlight=range#range-patterns /// [`for`]: keyword.for.html -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 mod in_keyword {} #[doc(keyword = "let")] @@ -895,6 +946,15 @@ mod mod_keyword {} /// // x is no longer available /// ``` /// +/// `move` is also valid before an async block. +/// +/// ```rust +/// let capture = "hello"; +/// let block = async move { +/// println!("rust says {} from async block", capture); +/// }; +/// ``` +/// /// For more information on the `move` keyword, see the [closure]'s section /// of the Rust book or the [threads] section /// @@ -916,9 +976,15 @@ mod mut_keyword {} // /// Make an item visible to others. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// The keyword `pub` makes any module, function, or data structure accessible from inside +/// of external modules. The `pub` keyword may also be used in a `use` declaration to re-export +/// an identifier from a namespace. /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// For more information on the `pub` keyword, please see the visibility section +/// of the [reference] and for some examples, see [Rust by Example]. +/// +/// [reference]:../reference/visibility-and-privacy.html?highlight=pub#visibility-and-privacy +/// [Rust by Example]:../rust-by-example/mod/visibility.html mod pub_keyword {} #[doc(keyword = "ref")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 78898ac3812..eb30b4f6359 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -233,14 +233,14 @@ #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] -#![feature(atomic_mut_ptr)] #![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(asm)] -#![feature(assoc_int_consts)] #![feature(associated_type_bounds)] +#![feature(atomic_mut_ptr)] #![feature(box_syntax)] #![feature(c_variadic)] +#![cfg_attr(not(bootstrap), feature(cfg_accessible))] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] @@ -256,7 +256,6 @@ #![feature(doc_cfg)] #![feature(doc_keyword)] #![feature(doc_masked)] -#![feature(doc_spotlight)] #![feature(dropck_eyepatch)] #![feature(duration_constants)] #![feature(exact_size_is_empty)] @@ -294,7 +293,8 @@ #![feature(shrink_to)] #![feature(slice_concat_ext)] #![feature(slice_internals)] -#![feature(specialization)] +#![cfg_attr(bootstrap, feature(specialization))] +#![cfg_attr(not(bootstrap), feature(min_specialization))] #![feature(staged_api)] #![feature(std_internals)] #![feature(stdsimd)] @@ -310,6 +310,7 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(yk_swt)] +#![feature(vec_into_raw_parts)] // NB: the above list is sorted to minimize merge conflicts. #![default_lib_allocator] @@ -551,6 +552,9 @@ pub use core::{ trace_macros, }; +#[stable(feature = "core_primitive", since = "1.43.0")] +pub use core::primitive; + // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 9e1ac8754d9..7fd7de56f46 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -185,7 +185,7 @@ macro_rules! eprintln { /// builds or when debugging in release mode is significantly faster. /// /// Note that the macro is intended as a debugging tool and therefore you -/// should avoid having uses of it in version control for longer periods. +/// should avoid having uses of it in version control for long periods. /// Use cases involving debug output that should be added to version control /// are better served by macros such as [`debug!`] from the [`log`] crate. /// diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index a59d7f0263b..57cba6b1f7a 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -901,7 +901,7 @@ impl ToSocketAddrs for str { type Iter = vec::IntoIter; fn to_socket_addrs(&self) -> io::Result> { // try to parse as a regular SocketAddr first - if let Some(addr) = self.parse().ok() { + if let Ok(addr) = self.parse() { return Ok(vec![addr].into_iter()); } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 200b00b1195..edc28033c9b 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -651,7 +651,7 @@ impl Ipv4Addr { /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the - /// broadcast address `255.255.255.255`, but this implementation explicitely excludes it, since + /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since /// it is obviously not reserved for future use. /// /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index 868a7e261c4..3f38ee54710 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -206,7 +206,7 @@ impl<'a> Parser<'a> { } // read `::` if previous code parsed less than 8 groups - if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() { + if self.read_given_char(':').is_none() || self.read_given_char(':').is_none() { return None; } diff --git a/src/libstd/os/linux/fs.rs b/src/libstd/os/linux/fs.rs index dd71201b50b..d22b44a0666 100644 --- a/src/libstd/os/linux/fs.rs +++ b/src/libstd/os/linux/fs.rs @@ -34,7 +34,7 @@ pub trait MetadataExt { /// } /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", reason = "other methods of this trait are now prefered")] + #[rustc_deprecated(since = "1.8.0", reason = "other methods of this trait are now preferred")] #[allow(deprecated)] fn as_raw_stat(&self) -> &raw::stat; diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 8b12aaaa7e2..10078bd4aee 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -14,7 +14,6 @@ use crate::fmt; use crate::intrinsics; use crate::mem::{self, ManuallyDrop}; use crate::process; -use crate::raw; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::stdio::panic_output; use crate::sys_common::backtrace::{self, RustBacktrace}; @@ -41,12 +40,7 @@ use realstd::io::set_panic; // hook up these functions, but it is not this day! #[allow(improper_ctypes)] extern "C" { - fn __rust_maybe_catch_panic( - f: fn(*mut u8), - data: *mut u8, - data_ptr: *mut usize, - vtable_ptr: *mut usize, - ) -> u32; + fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static); /// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings. /// It cannot be `Box` because the other end of this call does not depend @@ -247,54 +241,88 @@ pub unsafe fn r#try R>(f: F) -> Result> union Data { f: ManuallyDrop, r: ManuallyDrop, + p: ManuallyDrop>, } // We do some sketchy operations with ownership here for the sake of - // performance. We can only pass pointers down to - // `__rust_maybe_catch_panic` (can't pass objects by value), so we do all - // the ownership tracking here manually using a union. + // performance. We can only pass pointers down to `do_call` (can't pass + // objects by value), so we do all the ownership tracking here manually + // using a union. // // We go through a transition where: // - // * First, we set the data to be the closure that we're going to call. + // * First, we set the data field `f` to be the argumentless closure that we're going to call. // * When we make the function call, the `do_call` function below, we take - // ownership of the function pointer. At this point the `Data` union is + // ownership of the function pointer. At this point the `data` union is // entirely uninitialized. // * If the closure successfully returns, we write the return value into the - // data's return slot. Note that `ptr::write` is used as it's overwriting - // uninitialized data. - // * Finally, when we come back out of the `__rust_maybe_catch_panic` we're + // data's return slot (field `r`). + // * If the closure panics (`do_catch` below), we write the panic payload into field `p`. + // * Finally, when we come back out of the `try` intrinsic we're // in one of two states: // // 1. The closure didn't panic, in which case the return value was - // filled in. We move it out of `data` and return it. - // 2. The closure panicked, in which case the return value wasn't - // filled in. In this case the entire `data` union is invalid, so - // there is no need to drop anything. + // filled in. We move it out of `data.r` and return it. + // 2. The closure panicked, in which case the panic payload was + // filled in. We move it out of `data.p` and return it. // // Once we stack all that together we should have the "most efficient' // method of calling a catch panic whilst juggling ownership. - let mut any_data = 0; - let mut any_vtable = 0; let mut data = Data { f: ManuallyDrop::new(f) }; - let r = __rust_maybe_catch_panic( - do_call::, - &mut data as *mut _ as *mut u8, - &mut any_data, - &mut any_vtable, - ); - - return if r == 0 { + let data_ptr = &mut data as *mut _ as *mut u8; + return if do_try(do_call::, data_ptr, do_catch::) == 0 { Ok(ManuallyDrop::into_inner(data.r)) } else { - update_panic_count(-1); - Err(mem::transmute(raw::TraitObject { - data: any_data as *mut _, - vtable: any_vtable as *mut _, - })) + Err(ManuallyDrop::into_inner(data.p)) }; + // Compatibility wrapper around the try intrinsic for bootstrap. + // + // We also need to mark it #[inline(never)] to work around a bug on MinGW + // targets: the unwinding implementation was relying on UB, but this only + // becomes a problem in practice if inlining is involved. + #[cfg(not(bootstrap))] + use intrinsics::r#try as do_try; + #[cfg(bootstrap)] + #[inline(never)] + unsafe fn do_try(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32 { + use crate::mem::MaybeUninit; + #[cfg(target_env = "msvc")] + type TryPayload = [u64; 2]; + #[cfg(not(target_env = "msvc"))] + type TryPayload = *mut u8; + + let mut payload: MaybeUninit = MaybeUninit::uninit(); + let payload_ptr = payload.as_mut_ptr() as *mut u8; + let r = intrinsics::r#try(try_fn, data, payload_ptr); + if r != 0 { + #[cfg(target_env = "msvc")] + { + catch_fn(data, payload_ptr) + } + #[cfg(not(target_env = "msvc"))] + { + catch_fn(data, payload.assume_init()) + } + } + r + } + + // We consider unwinding to be rare, so mark this function as cold. However, + // do not mark it no-inline -- that decision is best to leave to the + // optimizer (in most cases this function is not inlined even as a normal, + // non-cold function, though, as of the writing of this comment). + #[cold] + unsafe fn cleanup(payload: *mut u8) -> Box { + let obj = Box::from_raw(__rust_panic_cleanup(payload)); + update_panic_count(-1); + obj + } + + // See comment on do_try above for why #[inline(never)] is needed on bootstrap. + #[cfg_attr(bootstrap, inline(never))] + #[cfg_attr(not(bootstrap), inline)] fn do_call R, R>(data: *mut u8) { unsafe { let data = data as *mut Data; @@ -303,6 +331,19 @@ pub unsafe fn r#try R>(f: F) -> Result> data.r = ManuallyDrop::new(f()); } } + + // We *do* want this part of the catch to be inlined: this allows the + // compiler to properly track accesses to the Data union and optimize it + // away most of the time. + #[inline] + fn do_catch R, R>(data: *mut u8, payload: *mut u8) { + unsafe { + let data = data as *mut Data; + let data = &mut (*data); + let obj = cleanup(payload); + data.p = ManuallyDrop::new(obj); + } + } } /// Determines whether the current thread is unwinding because of panic. diff --git a/src/libstd/path.rs b/src/libstd/path.rs index a703cb748e0..b8361d3e825 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2011,7 +2011,7 @@ impl Path { #[stable(feature = "rust1", since = "1.0.0")] pub fn file_name(&self) -> Option<&OsStr> { self.components().next_back().and_then(|p| match p { - Component::Normal(p) => Some(p.as_ref()), + Component::Normal(p) => Some(p), _ => None, }) } diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index 7c0efe828c2..6712f5ba580 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -53,6 +53,15 @@ pub use core::prelude::v1::{ PartialEq, PartialOrd, RustcDecodable, RustcEncodable, }; +#[cfg(not(bootstrap))] +#[unstable( + feature = "cfg_accessible", + issue = "64797", + reason = "`cfg_accessible` is not fully implemented" +)] +#[doc(hidden)] +pub use core::prelude::v1::cfg_accessible; + // The file so far is equivalent to src/libcore/prelude/v1.rs, // and below to src/liballoc/prelude.rs. // Those files are duplicated rather than using glob imports diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index d4b41e11c0e..adad90f56d1 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -771,7 +771,7 @@ mod prim_tuple {} #[doc(primitive = "f32")] /// The 32-bit floating point type. /// -/// *[See also the `std::f32` module](f32/index.html).* +/// *[See also the `std::f32::consts` module](f32/consts/index.html).* /// #[stable(feature = "rust1", since = "1.0.0")] mod prim_f32 {} @@ -780,7 +780,7 @@ mod prim_f32 {} // /// The 64-bit floating point type. /// -/// *[See also the `std::f64` module](f64/index.html).* +/// *[See also the `std::f64::consts` module](f64/consts/index.html).* /// #[stable(feature = "rust1", since = "1.0.0")] mod prim_f64 {} @@ -788,80 +788,60 @@ mod prim_f64 {} #[doc(primitive = "i8")] // /// The 8-bit signed integer type. -/// -/// *[See also the `std::i8` module](i8/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_i8 {} #[doc(primitive = "i16")] // /// The 16-bit signed integer type. -/// -/// *[See also the `std::i16` module](i16/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_i16 {} #[doc(primitive = "i32")] // /// The 32-bit signed integer type. -/// -/// *[See also the `std::i32` module](i32/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_i32 {} #[doc(primitive = "i64")] // /// The 64-bit signed integer type. -/// -/// *[See also the `std::i64` module](i64/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_i64 {} #[doc(primitive = "i128")] // /// The 128-bit signed integer type. -/// -/// *[See also the `std::i128` module](i128/index.html).* #[stable(feature = "i128", since = "1.26.0")] mod prim_i128 {} #[doc(primitive = "u8")] // /// The 8-bit unsigned integer type. -/// -/// *[See also the `std::u8` module](u8/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_u8 {} #[doc(primitive = "u16")] // /// The 16-bit unsigned integer type. -/// -/// *[See also the `std::u16` module](u16/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_u16 {} #[doc(primitive = "u32")] // /// The 32-bit unsigned integer type. -/// -/// *[See also the `std::u32` module](u32/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_u32 {} #[doc(primitive = "u64")] // /// The 64-bit unsigned integer type. -/// -/// *[See also the `std::u64` module](u64/index.html).* #[stable(feature = "rust1", since = "1.0.0")] mod prim_u64 {} #[doc(primitive = "u128")] // /// The 128-bit unsigned integer type. -/// -/// *[See also the `std::u128` module](u128/index.html).* #[stable(feature = "i128", since = "1.26.0")] mod prim_u128 {} @@ -869,8 +849,6 @@ mod prim_u128 {} // /// The pointer-sized signed integer type. /// -/// *[See also the `std::isize` module](isize/index.html).* -/// /// The size of this primitive is how many bytes it takes to reference any /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. @@ -881,8 +859,6 @@ mod prim_isize {} // /// The pointer-sized unsigned integer type. /// -/// *[See also the `std::usize` module](usize/index.html).* -/// /// The size of this primitive is how many bytes it takes to reference any /// location in memory. For example, on a 32 bit target, this is 4 bytes /// and on a 64 bit target, this is 8 bytes. diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index c51aa7619db..0274268f69f 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -40,7 +40,7 @@ struct Consumer { tail: UnsafeCell<*mut Node>, // where to pop from tail_prev: AtomicPtr>, // where to pop from cache_bound: usize, // maximum cache size - cached_nodes: AtomicUsize, // number of nodes marked as cachable + cached_nodes: AtomicUsize, // number of nodes marked as cacheable addition: Addition, } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 6eeddc28512..0cb16b19d73 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -416,7 +416,7 @@ impl fmt::Debug for Mutex { impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { unsafe fn new(lock: &'mutex Mutex) -> LockResult> { - poison::map_result(lock.poison.borrow(), |guard| MutexGuard { lock: lock, poison: guard }) + poison::map_result(lock.poison.borrow(), |guard| MutexGuard { lock, poison: guard }) } } diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 61c4d0c2dbf..1e6b6c430be 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -331,14 +331,14 @@ impl Once { /// * `call_once` was called, but has not yet completed, /// * the `Once` instance is poisoned /// - /// It is also possible that immediately after `is_completed` - /// returns false, some other thread finishes executing - /// `call_once`. + /// This function returning `false` does not mean that `Once` has not been + /// executed. For example, it may have been executed in the time between + /// when `is_completed` starts executing and when it returns, in which case + /// the `false` return value would be stale (but still permissible). /// /// # Examples /// /// ``` - /// #![feature(once_is_completed)] /// use std::sync::Once; /// /// static INIT: Once = Once::new(); @@ -351,7 +351,6 @@ impl Once { /// ``` /// /// ``` - /// #![feature(once_is_completed)] /// use std::sync::Once; /// use std::thread; /// @@ -364,7 +363,7 @@ impl Once { /// assert!(handle.join().is_err()); /// assert_eq!(INIT.is_completed(), false); /// ``` - #[unstable(feature = "once_is_completed", issue = "54890")] + #[stable(feature = "once_is_completed", since = "1.43.0")] #[inline] pub fn is_completed(&self) -> bool { // An `Acquire` load is enough because that makes all the initialization diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index fdd29af8581..50f54dbf143 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -465,16 +465,13 @@ impl From for RwLock { impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { unsafe fn new(lock: &'rwlock RwLock) -> LockResult> { - poison::map_result(lock.poison.borrow(), |_| RwLockReadGuard { lock: lock }) + poison::map_result(lock.poison.borrow(), |_| RwLockReadGuard { lock }) } } impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { unsafe fn new(lock: &'rwlock RwLock) -> LockResult> { - poison::map_result(lock.poison.borrow(), |guard| RwLockWriteGuard { - lock: lock, - poison: guard, - }) + poison::map_result(lock.poison.borrow(), |guard| RwLockWriteGuard { lock, poison: guard }) } } diff --git a/src/libstd/sys/cloudabi/io.rs b/src/libstd/sys/cloudabi/io.rs index 976e122463d..d5f475b4310 100644 --- a/src/libstd/sys/cloudabi/io.rs +++ b/src/libstd/sys/cloudabi/io.rs @@ -1,5 +1,6 @@ use crate::mem; +#[derive(Copy, Clone)] pub struct IoSlice<'a>(&'a [u8]); impl<'a> IoSlice<'a> { diff --git a/src/libstd/sys/hermit/io.rs b/src/libstd/sys/hermit/io.rs index 976e122463d..d5f475b4310 100644 --- a/src/libstd/sys/hermit/io.rs +++ b/src/libstd/sys/hermit/io.rs @@ -1,5 +1,6 @@ use crate::mem; +#[derive(Copy, Clone)] pub struct IoSlice<'a>(&'a [u8]); impl<'a> IoSlice<'a> { diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S index ed4db287229..1f06c9da3a9 100644 --- a/src/libstd/sys/sgx/abi/entry.S +++ b/src/libstd/sys/sgx/abi/entry.S @@ -151,6 +151,7 @@ elf_entry: pushfq andq $~0x40400, (%rsp) popfq +/* check for abort */ bt $0,.Laborted(%rip) jc .Lreentry_panic .endm diff --git a/src/libstd/sys/sgx/abi/usercalls/alloc.rs b/src/libstd/sys/sgx/abi/usercalls/alloc.rs index b54c115a2b6..76a9b427b39 100644 --- a/src/libstd/sys/sgx/abi/usercalls/alloc.rs +++ b/src/libstd/sys/sgx/abi/usercalls/alloc.rs @@ -151,7 +151,7 @@ unsafe impl UserSafe for [T] { /// It is also possible to obtain a mutable reference `&mut UserRef`. Unlike /// regular mutable references, these are not exclusive. Userspace may always /// write to the backing memory at any time, so it can't be assumed that there -/// the pointed-to memory is uniquely borrowed. The two different refence types +/// the pointed-to memory is uniquely borrowed. The two different reference types /// are used solely to indicate intent: a mutable reference is for writing to /// user memory, an immutable reference for reading from user memory. #[unstable(feature = "sgx_platform", issue = "56975")] diff --git a/src/libstd/sys/sgx/io.rs b/src/libstd/sys/sgx/io.rs index 976e122463d..d5f475b4310 100644 --- a/src/libstd/sys/sgx/io.rs +++ b/src/libstd/sys/sgx/io.rs @@ -1,5 +1,6 @@ use crate::mem; +#[derive(Copy, Clone)] pub struct IoSlice<'a>(&'a [u8]); impl<'a> IoSlice<'a> { diff --git a/src/libstd/sys/unix/io.rs b/src/libstd/sys/unix/io.rs index b4a64e93c84..deb5ee76bd0 100644 --- a/src/libstd/sys/unix/io.rs +++ b/src/libstd/sys/unix/io.rs @@ -3,6 +3,7 @@ use crate::slice; use libc::{c_void, iovec}; +#[derive(Copy, Clone)] #[repr(transparent)] pub struct IoSlice<'a> { vec: iovec, diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 06876cb0614..fbcb006ecdf 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -156,7 +156,7 @@ where // On Unix-like platforms, libc::abort will unregister signal handlers // including the SIGABRT handler, preventing the abort from being blocked, and -// fclose streams, with the side effect of flushing them so libc bufferred +// fclose streams, with the side effect of flushing them so libc buffered // output will be printed. Additionally the shell will generally print a more // understandable error message like "Abort trap" rather than "Illegal // instruction" that intrinsics::abort would cause, as intrinsics::abort is diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 79b0dc02978..b37675e0a0a 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -280,7 +280,7 @@ impl Socket { }; let mut timeout = libc::timeval { tv_sec: secs, - tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, + tv_usec: dur.subsec_micros() as libc::suseconds_t, }; if timeout.tv_sec == 0 && timeout.tv_usec == 0 { timeout.tv_usec = 1; diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index e66d6fdc56a..859da691ad2 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -19,9 +19,9 @@ cfg_if::cfg_if! { if #[cfg(target_os = "fuchsia")] { // fuchsia doesn't have /dev/null } else if #[cfg(target_os = "redox")] { - const DEV_NULL: &'static str = "null:\0"; + const DEV_NULL: &str = "null:\0"; } else { - const DEV_NULL: &'static str = "/dev/null\0"; + const DEV_NULL: &str = "/dev/null\0"; } } @@ -287,9 +287,7 @@ impl CStringArray { fn construct_envp(env: BTreeMap, saw_nul: &mut bool) -> CStringArray { let mut result = CStringArray::with_capacity(env.len()); - for (k, v) in env { - let mut k: OsString = k.into(); - + for (mut k, v) in env { // Reserve additional space for '=' and null terminator k.reserve_exact(v.len() + 2); k.push("="); diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 528fe321efb..2626ca37cf8 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -13,6 +13,10 @@ impl Handler { pub unsafe fn new() -> Handler { make_handler() } + + fn null() -> Handler { + Handler { _data: crate::ptr::null_mut() } + } } impl Drop for Handler { @@ -41,8 +45,9 @@ mod imp { use libc::{mmap, munmap}; use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL}; use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE}; - use libc::{MAP_ANON, MAP_PRIVATE, PROT_READ, PROT_WRITE, SIGSEGV}; + use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV}; + use crate::sys::unix::os::page_size; use crate::sys_common::thread_info; #[cfg(any(target_os = "linux", target_os = "android"))] @@ -108,13 +113,20 @@ mod imp { } static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut(); + static mut NEED_ALTSTACK: bool = false; pub unsafe fn init() { let mut action: sigaction = mem::zeroed(); - action.sa_flags = SA_SIGINFO | SA_ONSTACK; - action.sa_sigaction = signal_handler as sighandler_t; - sigaction(SIGSEGV, &action, ptr::null_mut()); - sigaction(SIGBUS, &action, ptr::null_mut()); + for &signal in &[SIGSEGV, SIGBUS] { + sigaction(signal, ptr::null_mut(), &mut action); + // Configure our signal handler if one is not already set. + if action.sa_sigaction == SIG_DFL { + action.sa_flags = SA_SIGINFO | SA_ONSTACK; + action.sa_sigaction = signal_handler as sighandler_t; + sigaction(signal, &action, ptr::null_mut()); + NEED_ALTSTACK = true; + } + } let handler = make_handler(); MAIN_ALTSTACK = handler._data; @@ -126,12 +138,22 @@ mod imp { } unsafe fn get_stackp() -> *mut libc::c_void { - let stackp = - mmap(ptr::null_mut(), SIGSTKSZ, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + let stackp = mmap( + ptr::null_mut(), + SIGSTKSZ + page_size(), + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, + -1, + 0, + ); if stackp == MAP_FAILED { panic!("failed to allocate an alternative stack"); } - stackp + let guard_result = libc::mprotect(stackp, page_size(), PROT_NONE); + if guard_result != 0 { + panic!("failed to set up alternative stack guard page"); + } + stackp.add(page_size()) } #[cfg(any( @@ -152,6 +174,9 @@ mod imp { } pub unsafe fn make_handler() -> Handler { + if !NEED_ALTSTACK { + return Handler::null(); + } let mut stack = mem::zeroed(); sigaltstack(ptr::null(), &mut stack); // Configure alternate signal stack, if one is not already set. @@ -160,7 +185,7 @@ mod imp { sigaltstack(&stack, ptr::null_mut()); Handler { _data: stack.ss_sp as *mut libc::c_void } } else { - Handler { _data: ptr::null_mut() } + Handler::null() } } @@ -176,7 +201,9 @@ mod imp { ss_size: SIGSTKSZ, }; sigaltstack(&stack, ptr::null_mut()); - munmap(handler._data, SIGSTKSZ); + // We know from `get_stackp` that the alternate stack we installed is part of a mapping + // that started one page earlier, so walk back a page and unmap from there. + munmap(handler._data.sub(page_size()), SIGSTKSZ + page_size()); } } } @@ -191,14 +218,12 @@ mod imp { target_os = "openbsd" )))] mod imp { - use crate::ptr; - pub unsafe fn init() {} pub unsafe fn cleanup() {} pub unsafe fn make_handler() -> super::Handler { - super::Handler { _data: ptr::null_mut() } + super::Handler::null() } pub unsafe fn drop_handler(_handler: &mut super::Handler) {} diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 3ca778354e4..674d4c71138 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -255,8 +255,9 @@ pub mod guard { #[cfg(target_os = "macos")] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { - let stackaddr = libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - - libc::pthread_get_stacksize_np(libc::pthread_self()); + let th = libc::pthread_self(); + let stackaddr = + libc::pthread_get_stackaddr_np(th) as usize - libc::pthread_get_stacksize_np(th); Some(stackaddr as *mut libc::c_void) } diff --git a/src/libstd/sys/vxworks/io.rs b/src/libstd/sys/vxworks/io.rs index f1a2c8446ff..0f68ebf8da9 100644 --- a/src/libstd/sys/vxworks/io.rs +++ b/src/libstd/sys/vxworks/io.rs @@ -3,6 +3,7 @@ use crate::slice; use libc::{c_void, iovec}; +#[derive(Copy, Clone)] #[repr(transparent)] pub struct IoSlice<'a> { vec: iovec, diff --git a/src/libstd/sys/vxworks/mod.rs b/src/libstd/sys/vxworks/mod.rs index 12bbfa1d4e1..e23191c9431 100644 --- a/src/libstd/sys/vxworks/mod.rs +++ b/src/libstd/sys/vxworks/mod.rs @@ -103,7 +103,7 @@ where // On Unix-like platforms, libc::abort will unregister signal handlers // including the SIGABRT handler, preventing the abort from being blocked, and -// fclose streams, with the side effect of flushing them so libc bufferred +// fclose streams, with the side effect of flushing them so libc buffered // output will be printed. Additionally the shell will generally print a more // understandable error message like "Abort trap" rather than "Illegal // instruction" that intrinsics::abort would cause, as intrinsics::abort is diff --git a/src/libstd/sys/wasi/fd.rs b/src/libstd/sys/wasi/fd.rs index 00327c1743c..8458ded5db0 100644 --- a/src/libstd/sys/wasi/fd.rs +++ b/src/libstd/sys/wasi/fd.rs @@ -13,19 +13,15 @@ pub struct WasiFd { fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] { assert_eq!(mem::size_of::>(), mem::size_of::()); assert_eq!(mem::align_of::>(), mem::align_of::()); - /// SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout - unsafe { - mem::transmute(a) - } + // SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout + unsafe { mem::transmute(a) } } fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] { assert_eq!(mem::size_of::>(), mem::size_of::()); assert_eq!(mem::align_of::>(), mem::align_of::()); - /// SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout - unsafe { - mem::transmute(a) - } + // SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout + unsafe { mem::transmute(a) } } impl WasiFd { diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index 04bfdf67e12..a11f61fdd69 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -12,7 +12,6 @@ use crate::sys::time::SystemTime; use crate::sys::unsupported; use crate::sys_common::FromInner; -pub use crate::sys_common::fs::copy; pub use crate::sys_common::fs::remove_dir_all; pub struct File { @@ -647,3 +646,12 @@ fn open_parent(p: &Path) -> io::Result<(ManuallyDrop, PathBuf)> { pub fn osstr2str(f: &OsStr) -> io::Result<&str> { f.to_str().ok_or_else(|| io::Error::new(io::ErrorKind::Other, "input must be utf-8")) } + +pub fn copy(from: &Path, to: &Path) -> io::Result { + use crate::fs::File; + + let mut reader = File::open(from)?; + let mut writer = File::create(to)?; + + io::copy(&mut reader, &mut writer) +} diff --git a/src/libstd/sys/wasi/io.rs b/src/libstd/sys/wasi/io.rs index ee20ea6dab8..0ad2e152855 100644 --- a/src/libstd/sys/wasi/io.rs +++ b/src/libstd/sys/wasi/io.rs @@ -1,6 +1,7 @@ use crate::marker::PhantomData; use crate::slice; +#[derive(Copy, Clone)] #[repr(transparent)] pub struct IoSlice<'a> { vec: wasi::Ciovec, diff --git a/src/libstd/sys/wasm/io.rs b/src/libstd/sys/wasm/io.rs index 976e122463d..d5f475b4310 100644 --- a/src/libstd/sys/wasm/io.rs +++ b/src/libstd/sys/wasm/io.rs @@ -1,5 +1,6 @@ use crate::mem; +#[derive(Copy, Clone)] pub struct IoSlice<'a>(&'a [u8]); impl<'a> IoSlice<'a> { diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 4d377341be3..7f93ef87953 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -295,6 +295,7 @@ pub struct WSADATA { pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1], } +#[derive(Copy, Clone)] #[repr(C)] pub struct WSABUF { pub len: ULONG, @@ -1044,6 +1045,10 @@ compat_fn! { _dwBufferSize: DWORD) -> BOOL { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } + pub fn GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime: LPFILETIME) + -> () { + GetSystemTimeAsFileTime(lpSystemTimeAsFileTime) + } pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE, SRWLock: PSRWLOCK, dwMilliseconds: DWORD, diff --git a/src/libstd/sys/windows/io.rs b/src/libstd/sys/windows/io.rs index 9d8018fd5e8..5525d283252 100644 --- a/src/libstd/sys/windows/io.rs +++ b/src/libstd/sys/windows/io.rs @@ -2,6 +2,7 @@ use crate::marker::PhantomData; use crate::slice; use crate::sys::c; +#[derive(Copy, Clone)] #[repr(transparent)] pub struct IoSlice<'a> { vec: c::WSABUF, diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 86667ca7ab2..900260169c7 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -74,7 +74,7 @@ impl SystemTime { pub fn now() -> SystemTime { unsafe { let mut t: SystemTime = mem::zeroed(); - c::GetSystemTimeAsFileTime(&mut t.t); + c::GetSystemTimePreciseAsFileTime(&mut t.t); t } } diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 289ee07babf..2c7ba8f8ea1 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -70,7 +70,7 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| { output_filename(fmt, bows, print_fmt, cwd.as_ref()) }; - write!(fmt, "stack backtrace:\n")?; + writeln!(fmt, "stack backtrace:")?; let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path); bt_fmt.add_context()?; let mut idx = 0; diff --git a/src/libstd/sys_common/process.rs b/src/libstd/sys_common/process.rs index 042641852b3..f3a2962098b 100644 --- a/src/libstd/sys_common/process.rs +++ b/src/libstd/sys_common/process.rs @@ -47,7 +47,7 @@ impl CommandEnv { } } for (key, maybe_val) in self.vars.iter() { - if let &Some(ref val) = maybe_val { + if let Some(ref val) = maybe_val { env::set_var(key, val); } else { env::remove_var(key); diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 1d96cdfe460..498950e6821 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -599,24 +599,16 @@ impl Wtf8 { #[inline] fn final_lead_surrogate(&self) -> Option { - let len = self.len(); - if len < 3 { - return None; - } - match &self.bytes[(len - 3)..] { - &[0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), + match self.bytes { + [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)), _ => None, } } #[inline] fn initial_trail_surrogate(&self) -> Option { - let len = self.len(); - if len < 3 { - return None; - } - match &self.bytes[..3] { - &[0xED, b2 @ 0xB0..=0xBF, b3] => Some(decode_surrogate(b2, b3)), + match self.bytes { + [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(b2, b3)), _ => None, } } diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 68a54915873..c36e78b1d00 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -284,7 +284,7 @@ impl Instant { } /// Returns the amount of time elapsed from another instant to this one, - /// or zero duration if that instant is earlier than this one. + /// or zero duration if that instant is later than this one. /// /// # Examples /// diff --git a/src/libsyntax/README.md b/src/libsyntax/README.md deleted file mode 100644 index daa252ef455..00000000000 --- a/src/libsyntax/README.md +++ /dev/null @@ -1,9 +0,0 @@ -The `syntax` crate contains those things concerned purely with syntax -– that is, the AST ("abstract syntax tree"), parser, pretty-printer, -lexer, macro expander, and utilities for traversing ASTs. - -For more information about how these things work in rustc, see the -rustc guide: - -- [Parsing](https://rust-lang.github.io/rustc-guide/the-parser.html) -- [Macro Expansion](https://rust-lang.github.io/rustc-guide/macro-expansion.html) diff --git a/src/libtest/cli.rs b/src/libtest/cli.rs index 778600b2196..5317063b80d 100644 --- a/src/libtest/cli.rs +++ b/src/libtest/cli.rs @@ -273,7 +273,7 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes { Ok(test_opts) } -// FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566 +// FIXME: Copied from librustc_ast until linkage errors are resolved. Issue #47566 fn is_nightly() -> bool { // Whether this is a feature-staged build, i.e., on the beta or stable channel let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); @@ -283,7 +283,7 @@ fn is_nightly() -> bool { bootstrap || !disable_unstable_features } -// Gets the CLI options assotiated with `report-time` feature. +// Gets the CLI options associated with `report-time` feature. fn get_time_options( matches: &getopts::Matches, allow_unstable: bool, diff --git a/src/libtest/console.rs b/src/libtest/console.rs index 149c9202e6e..ff741e3bd53 100644 --- a/src/libtest/console.rs +++ b/src/libtest/console.rs @@ -169,7 +169,7 @@ pub fn list_tests_console(opts: &TestOpts, tests: Vec) -> io::Res if !quiet { if ntest != 0 || nbench != 0 { - writeln!(output, "")?; + writeln!(output)?; } writeln!(output, "{}, {}", plural(ntest, "test"), plural(nbench, "benchmark"))?; diff --git a/src/libtest/formatters/json.rs b/src/libtest/formatters/json.rs index 863cad9f9d7..9ebc991d638 100644 --- a/src/libtest/formatters/json.rs +++ b/src/libtest/formatters/json.rs @@ -80,7 +80,7 @@ impl OutputFormatter for JsonFormatter { state: &ConsoleTestState, ) -> io::Result<()> { let display_stdout = state.options.display_output || *result != TestResult::TrOk; - let stdout = if display_stdout && stdout.len() > 0 { + let stdout = if display_stdout && !stdout.is_empty() { Some(String::from_utf8_lossy(stdout)) } else { None diff --git a/src/libtest/formatters/mod.rs b/src/libtest/formatters/mod.rs index a64c0fc263d..1fb840520a6 100644 --- a/src/libtest/formatters/mod.rs +++ b/src/libtest/formatters/mod.rs @@ -36,5 +36,5 @@ pub(crate) fn write_stderr_delimiter(test_output: &mut Vec, test_name: &Test Some(_) => test_output.push(b'\n'), None => (), } - write!(test_output, "---- {} stderr ----\n", test_name).unwrap(); + writeln!(test_output, "---- {} stderr ----", test_name).unwrap(); } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index de001cacbe1..55f9df9caaf 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -13,7 +13,7 @@ // running tests while providing a base that other test frameworks may // build off of. -// N.B., this is also specified in this crate's Cargo.toml, but libsyntax contains logic specific to +// N.B., this is also specified in this crate's Cargo.toml, but librustc_ast contains logic specific to // this crate, which relies on this attribute (rather than the value of `--crate-name` passed by // cargo) to detect this crate. @@ -96,7 +96,7 @@ use time::TestExecTime; // Process exit code to be used to indicate test failures. const ERROR_EXIT_CODE: i32 = 101; -const SECONDARY_TEST_INVOKER_VAR: &'static str = "__RUST_TEST_INVOKE"; +const SECONDARY_TEST_INVOKER_VAR: &str = "__RUST_TEST_INVOKE"; // The default console test runner. It accepts the command line // arguments and a vector of test_descs. @@ -158,7 +158,7 @@ pub fn test_main_static_abort(tests: &[&TestDescAndFn]) { .filter(|test| test.desc.name.as_slice() == name) .map(make_owned_test) .next() - .expect(&format!("couldn't find a test with the provided name '{}'", name)); + .unwrap_or_else(|| panic!("couldn't find a test with the provided name '{}'", name)); let TestDescAndFn { desc, testfn } = test; let testfn = match testfn { StaticTestFn(f) => f, diff --git a/src/libtest/options.rs b/src/libtest/options.rs index 7db164c269a..8e7bd8de924 100644 --- a/src/libtest/options.rs +++ b/src/libtest/options.rs @@ -41,7 +41,7 @@ pub enum OutputFormat { Json, } -/// Whether ignored test should be runned or not +/// Whether ignored test should be run or not #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum RunIgnored { Yes, diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index aab8d012fdf..077005371c0 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -204,7 +204,7 @@ impl Stats for [f64] { } fn median(&self) -> f64 { - self.percentile(50 as f64) + self.percentile(50_f64) } fn var(&self) -> f64 { @@ -230,7 +230,7 @@ impl Stats for [f64] { } fn std_dev_pct(&self) -> f64 { - let hundred = 100 as f64; + let hundred = 100_f64; (self.std_dev() / self.mean()) * hundred } @@ -244,7 +244,7 @@ impl Stats for [f64] { } fn median_abs_dev_pct(&self) -> f64 { - let hundred = 100 as f64; + let hundred = 100_f64; (self.median_abs_dev() / self.median()) * hundred } @@ -257,11 +257,11 @@ impl Stats for [f64] { fn quartiles(&self) -> (f64, f64, f64) { let mut tmp = self.to_vec(); local_sort(&mut tmp); - let first = 25f64; + let first = 25_f64; let a = percentile_of_sorted(&tmp, first); - let second = 50f64; + let second = 50_f64; let b = percentile_of_sorted(&tmp, second); - let third = 75f64; + let third = 75_f64; let c = percentile_of_sorted(&tmp, third); (a, b, c) } @@ -281,7 +281,7 @@ fn percentile_of_sorted(sorted_samples: &[f64], pct: f64) -> f64 { } let zero: f64 = 0.0; assert!(zero <= pct); - let hundred = 100f64; + let hundred = 100_f64; assert!(pct <= hundred); if pct == hundred { return sorted_samples[sorted_samples.len() - 1]; @@ -307,7 +307,7 @@ pub fn winsorize(samples: &mut [f64], pct: f64) { let mut tmp = samples.to_vec(); local_sort(&mut tmp); let lo = percentile_of_sorted(&tmp, pct); - let hundred = 100 as f64; + let hundred = 100_f64; let hi = percentile_of_sorted(&tmp, hundred - pct); for samp in samples { if *samp > hi { diff --git a/src/libtest/test_result.rs b/src/libtest/test_result.rs index bfa572c887a..465f3f8f994 100644 --- a/src/libtest/test_result.rs +++ b/src/libtest/test_result.rs @@ -27,7 +27,7 @@ pub enum TestResult { unsafe impl Send for TestResult {} /// Creates a `TestResult` depending on the raw result of test execution -/// and assotiated data. +/// and associated data. pub fn calc_result<'a>( desc: &TestDesc, task_result: Result<(), &'a (dyn Any + 'static + Send)>, @@ -40,7 +40,7 @@ pub fn calc_result<'a>( let maybe_panic_str = err .downcast_ref::() .map(|e| &**e) - .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e)); + .or_else(|| err.downcast_ref::<&'static str>().copied()); if maybe_panic_str.map(|e| e.contains(msg)).unwrap_or(false) { TestResult::TrOk diff --git a/src/libtest/types.rs b/src/libtest/types.rs index 2619f99592a..5b75d2f367f 100644 --- a/src/libtest/types.rs +++ b/src/libtest/types.rs @@ -59,10 +59,10 @@ impl TestName { } pub fn with_padding(&self, padding: NamePadding) -> TestName { - let name = match self { - &TestName::StaticTestName(name) => Cow::Borrowed(name), - &TestName::DynTestName(ref name) => Cow::Owned(name.clone()), - &TestName::AlignedTestName(ref name, _) => name.clone(), + let name = match *self { + TestName::StaticTestName(name) => Cow::Borrowed(name), + TestName::DynTestName(ref name) => Cow::Owned(name.clone()), + TestName::AlignedTestName(ref name, _) => name.clone(), }; TestName::AlignedTestName(name, padding) diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index a24808b3250..0628e5d2fc0 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -33,8 +33,13 @@ fn main() { } else if target.contains("dragonfly") { println!("cargo:rustc-link-lib=gcc_pic"); } else if target.contains("pc-windows-gnu") { - println!("cargo:rustc-link-lib=static-nobundle=gcc_eh"); - println!("cargo:rustc-link-lib=static-nobundle=pthread"); + // This is handled in the target spec with late_link_args_[static|dynamic] + + // cfg!(bootstrap) doesn't work in build scripts + if env::var("RUSTC_STAGE").ok() == Some("0".to_string()) { + println!("cargo:rustc-link-lib=static-nobundle=gcc_eh"); + println!("cargo:rustc-link-lib=static-nobundle=pthread"); + } } else if target.contains("uwp-windows-gnu") { println!("cargo:rustc-link-lib=unwind"); } else if target.contains("fuchsia") { diff --git a/src/llvm-project b/src/llvm-project index d7cdb435922..9f65ad05735 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit d7cdb4359223be265da34ebeaa00b92b7c5419fd +Subproject commit 9f65ad057357b307180955831968f79e74090a90 diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index f92ff9f071a..bd1946133e8 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -60,37 +60,36 @@ pub mod eh_frames { } // Unwind info registration/deregistration routines. - // See the docs of `unwind` module in libstd. + // See the docs of libpanic_unwind. extern "C" { fn rust_eh_register_frames(eh_frame_begin: *const u8, object: *mut u8); fn rust_eh_unregister_frames(eh_frame_begin: *const u8, object: *mut u8); } - unsafe fn init() { + unsafe extern "C" fn init() { // register unwind info on module startup rust_eh_register_frames(&__EH_FRAME_BEGIN__ as *const u8, &mut OBJ as *mut _ as *mut u8); } - unsafe fn uninit() { + unsafe extern "C" fn uninit() { // unregister on shutdown rust_eh_unregister_frames(&__EH_FRAME_BEGIN__ as *const u8, &mut OBJ as *mut _ as *mut u8); } - // MSVC-specific init/uninit routine registration - pub mod ms_init { - // .CRT$X?? sections are roughly analogous to ELF's .init_array and .fini_array, - // except that they exploit the fact that linker will sort them alphabitically, - // so e.g., sections with names between .CRT$XIA and .CRT$XIZ are guaranteed to be - // placed between those two, without requiring any ordering of objects on the linker - // command line. - // Note that ordering of same-named sections from different objects is not guaranteed. - // Since .CRT$XIA contains init array's header symbol, which must always come first, - // we place our initialization callback into .CRT$XIB. + // MinGW-specific init/uninit routine registration + pub mod mingw_init { + // MinGW's startup objects (crt0.o / dllcrt0.o) will invoke global constructors in the + // .ctors and .dtors sections on startup and exit. In the case of DLLs, this is done when + // the DLL is loaded and unloaded. + // + // The linker will sort the sections, which ensures that our callbacks are located at the + // end of the list. Since constructors are run in reverse order, this ensures that our + // callbacks are the first and last ones executed. - #[link_section = ".CRT$XIB"] // .CRT$XI? : C initialization callbacks - pub static P_INIT: unsafe fn() = super::init; + #[link_section = ".ctors.65535"] // .ctors.* : C initialization callbacks + pub static P_INIT: unsafe extern "C" fn() = super::init; - #[link_section = ".CRT$XTY"] // .CRT$XT? : C termination callbacks - pub static P_UNINIT: unsafe fn() = super::uninit; + #[link_section = ".dtors.65535"] // .dtors.* : C termination callbacks + pub static P_UNINIT: unsafe extern "C" fn() = super::uninit; } } diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 15e2251d763..90d24d20737 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -640,6 +640,62 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, return LLVMRustResult::Success; } +extern "C" typedef void (*LLVMRustSelfProfileBeforePassCallback)(void*, // LlvmSelfProfiler + const char*, // pass name + const char*); // IR name +extern "C" typedef void (*LLVMRustSelfProfileAfterPassCallback)(void*); // LlvmSelfProfiler + +#if LLVM_VERSION_GE(9, 0) + +std::string LLVMRustwrappedIrGetName(const llvm::Any &WrappedIr) { + if (any_isa(WrappedIr)) + return any_cast(WrappedIr)->getName().str(); + if (any_isa(WrappedIr)) + return any_cast(WrappedIr)->getName().str(); + if (any_isa(WrappedIr)) + return any_cast(WrappedIr)->getName().str(); + if (any_isa(WrappedIr)) + return any_cast(WrappedIr)->getName(); + return ""; +} + + +void LLVMSelfProfileInitializeCallbacks( + PassInstrumentationCallbacks& PIC, void* LlvmSelfProfiler, + LLVMRustSelfProfileBeforePassCallback BeforePassCallback, + LLVMRustSelfProfileAfterPassCallback AfterPassCallback) { + PIC.registerBeforePassCallback([LlvmSelfProfiler, BeforePassCallback]( + StringRef Pass, llvm::Any Ir) { + std::string PassName = Pass.str(); + std::string IrName = LLVMRustwrappedIrGetName(Ir); + BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str()); + return true; + }); + + PIC.registerAfterPassCallback( + [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) { + AfterPassCallback(LlvmSelfProfiler); + }); + + PIC.registerAfterPassInvalidatedCallback( + [LlvmSelfProfiler, AfterPassCallback](StringRef Pass) { + AfterPassCallback(LlvmSelfProfiler); + }); + + PIC.registerBeforeAnalysisCallback([LlvmSelfProfiler, BeforePassCallback]( + StringRef Pass, llvm::Any Ir) { + std::string PassName = Pass.str(); + std::string IrName = LLVMRustwrappedIrGetName(Ir); + BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str()); + }); + + PIC.registerAfterAnalysisCallback( + [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) { + AfterPassCallback(LlvmSelfProfiler); + }); +} +#endif + enum class LLVMRustOptStage { PreLinkNoLTO, PreLinkThinLTO, @@ -666,7 +722,10 @@ LLVMRustOptimizeWithNewPassManager( bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize, bool DisableSimplifyLibCalls, LLVMRustSanitizerOptions *SanitizerOptions, - const char *PGOGenPath, const char *PGOUsePath) { + const char *PGOGenPath, const char *PGOUsePath, + void* LlvmSelfProfiler, + LLVMRustSelfProfileBeforePassCallback BeforePassCallback, + LLVMRustSelfProfileAfterPassCallback AfterPassCallback) { #if LLVM_VERSION_GE(9, 0) Module *TheModule = unwrap(ModuleRef); TargetMachine *TM = unwrap(TMRef); @@ -685,6 +744,10 @@ LLVMRustOptimizeWithNewPassManager( StandardInstrumentations SI; SI.registerCallbacks(PIC); + if (LlvmSelfProfiler){ + LLVMSelfProfileInitializeCallbacks(PIC,LlvmSelfProfiler,BeforePassCallback,AfterPassCallback); + } + Optional PGOOpt; if (PGOGenPath) { assert(!PGOUsePath); @@ -761,14 +824,14 @@ LLVMRustOptimizeWithNewPassManager( } if (SanitizerOptions->SanitizeAddress) { - // FIXME: Rust does not expose the UseAfterScope option. PipelineStartEPCallbacks.push_back([&](ModulePassManager &MPM) { MPM.addPass(RequireAnalysisPass()); }); OptimizerLastEPCallbacks.push_back( [SanitizerOptions](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) { FPM.addPass(AddressSanitizerPass( - /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover)); + /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover, + /*UseAfterScope=*/true)); } ); PipelineStartEPCallbacks.push_back( @@ -805,8 +868,10 @@ LLVMRustOptimizeWithNewPassManager( } else { for (const auto &C : PipelineStartEPCallbacks) PB.registerPipelineStartEPCallback(C); - for (const auto &C : OptimizerLastEPCallbacks) - PB.registerOptimizerLastEPCallback(C); + if (OptStage != LLVMRustOptStage::PreLinkThinLTO) { + for (const auto &C : OptimizerLastEPCallbacks) + PB.registerOptimizerLastEPCallback(C); + } switch (OptStage) { case LLVMRustOptStage::PreLinkNoLTO: @@ -814,6 +879,12 @@ LLVMRustOptimizeWithNewPassManager( break; case LLVMRustOptStage::PreLinkThinLTO: MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager); + if (!OptimizerLastEPCallbacks.empty()) { + FunctionPassManager FPM(DebugPassManager); + for (const auto &C : OptimizerLastEPCallbacks) + C(FPM, OptLevel); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } break; case LLVMRustOptStage::PreLinkFatLTO: MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager); diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index b04fc13892b..0542a61194c 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -113,20 +113,22 @@ extern "C" void LLVMRustPrintPassTimings() { TimerGroup::printAll(OS); } -extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M, - const char *Name) { - return wrap(unwrap(M)->getNamedValue(Name)); +extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M, const char *Name, + size_t NameLen) { + return wrap(unwrap(M)->getNamedValue(StringRef(Name, NameLen))); } extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, const char *Name, + size_t NameLen, LLVMTypeRef FunctionTy) { - return wrap( - unwrap(M)->getOrInsertFunction(Name, unwrap(FunctionTy)) + return wrap(unwrap(M) + ->getOrInsertFunction(StringRef(Name, NameLen), + unwrap(FunctionTy)) #if LLVM_VERSION_GE(9, 0) - .getCallee() + .getCallee() #endif - ); + ); } extern "C" LLVMValueRef @@ -396,22 +398,26 @@ static InlineAsm::AsmDialect fromRust(LLVMRustAsmDialect Dialect) { } } -extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, - char *Constraints, - LLVMBool HasSideEffects, - LLVMBool IsAlignStack, - LLVMRustAsmDialect Dialect) { - return wrap(InlineAsm::get(unwrap(Ty), AsmString, Constraints, +extern "C" LLVMValueRef +LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen, + char *Constraints, size_t ConstraintsLen, + LLVMBool HasSideEffects, LLVMBool IsAlignStack, + LLVMRustAsmDialect Dialect) { + return wrap(InlineAsm::get(unwrap(Ty), + StringRef(AsmString, AsmStringLen), + StringRef(Constraints, ConstraintsLen), HasSideEffects, IsAlignStack, fromRust(Dialect))); } -extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, - char *Constraints) { - return InlineAsm::Verify(unwrap(Ty), Constraints); +extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints, + size_t ConstraintsLen) { + return InlineAsm::Verify(unwrap(Ty), + StringRef(Constraints, ConstraintsLen)); } -extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm) { - unwrap(M)->appendModuleInlineAsm(StringRef(Asm)); +extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm, + size_t AsmLen) { + unwrap(M)->appendModuleInlineAsm(StringRef(Asm, AsmLen)); } typedef DIBuilder *LLVMRustDIBuilderRef; @@ -666,20 +672,24 @@ extern "C" void LLVMRustDIBuilderFinalize(LLVMRustDIBuilderRef Builder) { extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit( LLVMRustDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef, - const char *Producer, bool isOptimized, const char *Flags, - unsigned RuntimeVer, const char *SplitName, + const char *Producer, size_t ProducerLen, bool isOptimized, + const char *Flags, unsigned RuntimeVer, + const char *SplitName, size_t SplitNameLen, LLVMRustDebugEmissionKind Kind) { auto *File = unwrapDI(FileRef); - return wrap(Builder->createCompileUnit(Lang, File, Producer, isOptimized, - Flags, RuntimeVer, SplitName, + return wrap(Builder->createCompileUnit(Lang, File, StringRef(Producer, ProducerLen), + isOptimized, Flags, RuntimeVer, + StringRef(SplitName, SplitNameLen), fromRust(Kind))); } -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateFile(LLVMRustDIBuilderRef Builder, const char *Filename, - const char *Directory) { - return wrap(Builder->createFile(Filename, Directory)); +extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile( + LLVMRustDIBuilderRef Builder, + const char *Filename, size_t FilenameLen, + const char *Directory, size_t DirectoryLen) { + return wrap(Builder->createFile(StringRef(Filename, FilenameLen), + StringRef(Directory, DirectoryLen))); } extern "C" LLVMMetadataRef @@ -691,8 +701,10 @@ LLVMRustDIBuilderCreateSubroutineType(LLVMRustDIBuilderRef Builder, } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, - const char *LinkageName, LLVMMetadataRef File, unsigned LineNo, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, + const char *LinkageName, size_t LinkageNameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, unsigned ScopeLine, LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags, LLVMValueRef Fn, LLVMMetadataRef TParam, LLVMMetadataRef Decl) { @@ -706,8 +718,11 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( llvmFlags |= DINode::DIFlags::FlagMainSubprogram; #endif DISubprogram *Sub = Builder->createFunction( - unwrapDI(Scope), Name, LinkageName, unwrapDI(File), - LineNo, unwrapDI(Ty), ScopeLine, llvmFlags, + unwrapDI(Scope), + StringRef(Name, NameLen), + StringRef(LinkageName, LinkageNameLen), + unwrapDI(File), LineNo, + unwrapDI(Ty), ScopeLine, llvmFlags, llvmSPFlags, TParams, unwrapDIPtr(Decl)); #else bool IsLocalToUnit = isSet(SPFlags & LLVMRustDISPFlags::SPFlagLocalToUnit); @@ -717,8 +732,11 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagMainSubprogram)) llvmFlags |= DINode::DIFlags::FlagMainSubprogram; DISubprogram *Sub = Builder->createFunction( - unwrapDI(Scope), Name, LinkageName, unwrapDI(File), - LineNo, unwrapDI(Ty), IsLocalToUnit, IsDefinition, + unwrapDI(Scope), + StringRef(Name, NameLen), + StringRef(LinkageName, LinkageNameLen), + unwrapDI(File), LineNo, + unwrapDI(Ty), IsLocalToUnit, IsDefinition, ScopeLine, llvmFlags, IsOptimized, TParams, unwrapDIPtr(Decl)); #endif @@ -726,53 +744,59 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( return wrap(Sub); } -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name, - uint64_t SizeInBits, uint32_t AlignInBits, - unsigned Encoding) { - return wrap(Builder->createBasicType(Name, SizeInBits, Encoding)); +extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateBasicType( + LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen, + uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding) { + return wrap(Builder->createBasicType(StringRef(Name, NameLen), SizeInBits, Encoding)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType( LLVMRustDIBuilderRef Builder, LLVMMetadataRef PointeeTy, - uint64_t SizeInBits, uint32_t AlignInBits, const char *Name) { + uint64_t SizeInBits, uint32_t AlignInBits, unsigned AddressSpace, + const char *Name, size_t NameLen) { return wrap(Builder->createPointerType(unwrapDI(PointeeTy), SizeInBits, AlignInBits, - /* DWARFAddressSpace */ None, - Name)); + AddressSpace, + StringRef(Name, NameLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef DerivedFrom, LLVMMetadataRef Elements, unsigned RunTimeLang, LLVMMetadataRef VTableHolder, - const char *UniqueId) { + const char *UniqueId, size_t UniqueIdLen) { return wrap(Builder->createStructType( - unwrapDI(Scope), Name, unwrapDI(File), LineNumber, + unwrapDI(Scope), StringRef(Name, NameLen), + unwrapDI(File), LineNumber, SizeInBits, AlignInBits, fromRust(Flags), unwrapDI(DerivedFrom), DINodeArray(unwrapDI(Elements)), RunTimeLang, - unwrapDI(VTableHolder), UniqueId)); + unwrapDI(VTableHolder), StringRef(UniqueId, UniqueIdLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Discriminator, - LLVMMetadataRef Elements, const char *UniqueId) { + LLVMMetadataRef Elements, const char *UniqueId, size_t UniqueIdLen) { return wrap(Builder->createVariantPart( - unwrapDI(Scope), Name, unwrapDI(File), LineNumber, + unwrapDI(Scope), StringRef(Name, NameLen), + unwrapDI(File), LineNumber, SizeInBits, AlignInBits, fromRust(Flags), unwrapDI(Discriminator), - DINodeArray(unwrapDI(Elements)), UniqueId)); + DINodeArray(unwrapDI(Elements)), StringRef(UniqueId, UniqueIdLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Ty) { - return wrap(Builder->createMemberType(unwrapDI(Scope), Name, + return wrap(Builder->createMemberType(unwrapDI(Scope), + StringRef(Name, NameLen), unwrapDI(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, fromRust(Flags), unwrapDI(Ty))); @@ -780,14 +804,15 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType( LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, - const char *Name, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, - uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, + uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant, LLVMRustDIFlags Flags, LLVMMetadataRef Ty) { llvm::ConstantInt* D = nullptr; if (Discriminant) { D = unwrap(Discriminant); } - return wrap(Builder->createVariantMemberType(unwrapDI(Scope), Name, + return wrap(Builder->createVariantMemberType(unwrapDI(Scope), + StringRef(Name, NameLen), unwrapDI(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, D, fromRust(Flags), unwrapDI(Ty))); @@ -809,8 +834,10 @@ LLVMRustDIBuilderCreateLexicalBlockFile(LLVMRustDIBuilderRef Builder, } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name, - const char *LinkageName, LLVMMetadataRef File, unsigned LineNo, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Context, + const char *Name, size_t NameLen, + const char *LinkageName, size_t LinkageNameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, bool IsLocalToUnit, LLVMValueRef V, LLVMMetadataRef Decl = nullptr, uint32_t AlignInBits = 0) { llvm::GlobalVariable *InitVal = cast(unwrap(V)); @@ -826,7 +853,8 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( } llvm::DIGlobalVariableExpression *VarExpr = Builder->createGlobalVariableExpression( - unwrapDI(Context), Name, LinkageName, + unwrapDI(Context), StringRef(Name, NameLen), + StringRef(LinkageName, LinkageNameLen), unwrapDI(File), LineNo, unwrapDI(Ty), IsLocalToUnit, #if LLVM_VERSION_GE(10, 0) /* isDefined */ true, @@ -844,17 +872,20 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( LLVMRustDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope, - const char *Name, LLVMMetadataRef File, unsigned LineNo, + const char *Name, size_t NameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMRustDIFlags Flags, unsigned ArgNo, uint32_t AlignInBits) { if (Tag == 0x100) { // DW_TAG_auto_variable return wrap(Builder->createAutoVariable( - unwrapDI(Scope), Name, unwrapDI(File), LineNo, + unwrapDI(Scope), StringRef(Name, NameLen), + unwrapDI(File), LineNo, unwrapDI(Ty), AlwaysPreserve, fromRust(Flags), AlignInBits)); } else { return wrap(Builder->createParameterVariable( - unwrapDI(Scope), Name, ArgNo, unwrapDI(File), - LineNo, unwrapDI(Ty), AlwaysPreserve, fromRust(Flags))); + unwrapDI(Scope), StringRef(Name, NameLen), ArgNo, + unwrapDI(File), LineNo, + unwrapDI(Ty), AlwaysPreserve, fromRust(Flags))); } } @@ -892,50 +923,53 @@ extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( unwrap(InsertAtEnd))); } -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateEnumerator(LLVMRustDIBuilderRef Builder, - const char *Name, uint64_t Val) { - return wrap(Builder->createEnumerator(Name, Val)); +extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator( + LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen, + int64_t Value, bool IsUnsigned) { + return wrap(Builder->createEnumerator(StringRef(Name, NameLen), Value, IsUnsigned)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMMetadataRef Elements, LLVMMetadataRef ClassTy, bool IsScoped) { return wrap(Builder->createEnumerationType( - unwrapDI(Scope), Name, unwrapDI(File), LineNumber, + unwrapDI(Scope), StringRef(Name, NameLen), + unwrapDI(File), LineNumber, SizeInBits, AlignInBits, DINodeArray(unwrapDI(Elements)), unwrapDI(ClassTy), "", IsScoped)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, LLVMMetadataRef Elements, - unsigned RunTimeLang, const char *UniqueId) { + unsigned RunTimeLang, const char *UniqueId, size_t UniqueIdLen) { return wrap(Builder->createUnionType( - unwrapDI(Scope), Name, unwrapDI(File), LineNumber, - SizeInBits, AlignInBits, fromRust(Flags), - DINodeArray(unwrapDI(Elements)), RunTimeLang, UniqueId)); + unwrapDI(Scope), StringRef(Name, NameLen), unwrapDI(File), + LineNumber, SizeInBits, AlignInBits, fromRust(Flags), + DINodeArray(unwrapDI(Elements)), RunTimeLang, + StringRef(UniqueId, UniqueIdLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, LLVMMetadataRef Ty, LLVMMetadataRef File, unsigned LineNo, unsigned ColumnNo) { return wrap(Builder->createTemplateTypeParameter( - unwrapDI(Scope), Name, unwrapDI(Ty))); + unwrapDI(Scope), StringRef(Name, NameLen), unwrapDI(Ty))); } -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateNameSpace(LLVMRustDIBuilderRef Builder, - LLVMMetadataRef Scope, const char *Name, - LLVMMetadataRef File, unsigned LineNo) { +extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace( + LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, + const char *Name, size_t NameLen, bool ExportSymbols) { return wrap(Builder->createNameSpace( - unwrapDI(Scope), Name, - false // ExportSymbols (only relevant for C++ anonymous namespaces) - )); + unwrapDI(Scope), StringRef(Name, NameLen), ExportSymbols + )); } extern "C" void @@ -1295,12 +1329,11 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) { extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, unsigned NumArgs, - OperandBundleDef *Bundle, - const char *Name) { + OperandBundleDef *Bundle) { unsigned Len = Bundle ? 1 : 0; ArrayRef Bundles = makeArrayRef(Bundle, Len); return wrap(unwrap(B)->CreateCall( - unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles, Name)); + unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles)); } extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, diff --git a/src/stage0.txt b/src/stage0.txt index 14bffbadc06..4d9a91e38b3 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2020-01-30 +date: 2020-03-12 rustc: beta cargo: beta diff --git a/src/test/COMPILER_TESTS.md b/src/test/COMPILER_TESTS.md index 3f47ca834cd..ea540bd0b18 100644 --- a/src/test/COMPILER_TESTS.md +++ b/src/test/COMPILER_TESTS.md @@ -1,4 +1,4 @@ # Compiler Test Documentation Documentation for the compiler testing framework can be found in -[the rustc guide](https://rust-lang.github.io/rustc-guide/tests/intro.html). +[the rustc dev guide](https://rustc-dev-guide.rust-lang.org/tests/intro.html). diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs index f85ae0c0774..662519067d7 100644 --- a/src/test/codegen-units/partitioning/extern-drop-glue.rs +++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs @@ -2,23 +2,23 @@ // We specify -Z incremental here because we want to test the partitioning for // incremental compilation +// We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing // compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/extern-drop-glue -// compile-flags:-Zinline-in-all-cgus +// compile-flags:-Zinline-in-all-cgus -Copt-level=0 #![allow(dead_code)] -#![crate_type="rlib"] +#![crate_type = "rlib"] // aux-build:cgu_extern_drop_glue.rs extern crate cgu_extern_drop_glue; -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue[Internal] extern_drop_glue-mod1[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-fallback.cgu[External] struct LocalStruct(cgu_extern_drop_glue::Struct); //~ MONO_ITEM fn extern_drop_glue::user[0] @@ extern_drop_glue[External] -pub fn user() -{ - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue[Internal] +pub fn user() { + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-fallback.cgu[External] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); } @@ -28,9 +28,8 @@ pub mod mod1 { struct LocalStruct(cgu_extern_drop_glue::Struct); //~ MONO_ITEM fn extern_drop_glue::mod1[0]::user[0] @@ extern_drop_glue-mod1[External] - pub fn user() - { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-mod1[Internal] + pub fn user() { + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-fallback.cgu[External] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); } } diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs index 366af4d4c38..14a50bf5798 100644 --- a/src/test/codegen-units/partitioning/local-drop-glue.rs +++ b/src/test/codegen-units/partitioning/local-drop-glue.rs @@ -1,54 +1,45 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation +// We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing // compile-flags:-Zprint-mono-items=lazy -Zincremental=tmp/partitioning-tests/local-drop-glue -// compile-flags:-Zinline-in-all-cgus +// compile-flags:-Zinline-in-all-cgus -Copt-level=0 #![allow(dead_code)] -#![crate_type="rlib"] +#![crate_type = "rlib"] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue[Internal] local_drop_glue-mod1[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-fallback.cgu[External] struct Struct { - _a: u32 + _a: u32, } impl Drop for Struct { - //~ MONO_ITEM fn local_drop_glue::{{impl}}[0]::drop[0] @@ local_drop_glue[External] + //~ MONO_ITEM fn local_drop_glue::{{impl}}[0]::drop[0] @@ local_drop_glue-fallback.cgu[External] fn drop(&mut self) {} } -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue[Internal] +//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-fallback.cgu[External] struct Outer { - _a: Struct + _a: Struct, } //~ MONO_ITEM fn local_drop_glue::user[0] @@ local_drop_glue[External] -pub fn user() -{ - let _ = Outer { - _a: Struct { - _a: 0 - } - }; +pub fn user() { + let _ = Outer { _a: Struct { _a: 0 } }; } -pub mod mod1 -{ +pub mod mod1 { use super::Struct; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-mod1[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-fallback.cgu[External] struct Struct2 { _a: Struct, - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, local_drop_glue::Struct[0])> @@ local_drop_glue-mod1[Internal] + //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, local_drop_glue::Struct[0])> @@ local_drop_glue-fallback.cgu[Internal] _b: (u32, Struct), } //~ MONO_ITEM fn local_drop_glue::mod1[0]::user[0] @@ local_drop_glue-mod1[External] - pub fn user() - { - let _ = Struct2 { - _a: Struct { _a: 0 }, - _b: (0, Struct { _a: 0 }), - }; + pub fn user() { + let _ = Struct2 { _a: Struct { _a: 0 }, _b: (0, Struct { _a: 0 }) }; } } diff --git a/src/test/codegen/catch-unwind.rs b/src/test/codegen/catch-unwind.rs new file mode 100644 index 00000000000..3c9bc35d1c8 --- /dev/null +++ b/src/test/codegen/catch-unwind.rs @@ -0,0 +1,19 @@ +// compile-flags: -O + +#![crate_type = "lib"] + +extern "C" { + fn bar(); +} + +// CHECK-LABEL: @foo +#[no_mangle] +pub unsafe fn foo() -> i32 { + // CHECK: call void @bar + // CHECK: ret i32 0 + std::panic::catch_unwind(|| { + bar(); + 0 + }) + .unwrap() +} diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index a89ecdfd3a9..e53e75b339b 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -10,11 +10,11 @@ // CHECK: @STATIC = {{.*}}, align 4 // This checks the constants from inline_enum_const -// CHECK: @{{[0-9]+}} = {{.*}}, align 2 +// CHECK: @alloc5 = {{.*}}, align 2 // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @2, i32 0, i32 0, i32 0), {{.*}}, +// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @alloc15, i32 0, i32 0, i32 0), {{.*}} #[derive(Copy, Clone)] // repr(i16) is required for the {low,high}_align_const test diff --git a/src/test/codegen/debug-column-msvc.rs b/src/test/codegen/debug-column-msvc.rs new file mode 100644 index 00000000000..aad8b372a8a --- /dev/null +++ b/src/test/codegen/debug-column-msvc.rs @@ -0,0 +1,16 @@ +// Verify that no column information is emitted for MSVC targets +// +// only-msvc +// compile-flags: -C debuginfo=2 + +// CHECK-NOT: !DILexicalBlock({{.*}}column: {{.*}}) +// CHECK-NOT: !DILocation({{.*}}column: {{.*}}) + +pub fn add(a: u32, b: u32) -> u32 { + a + b +} + +fn main() { + let c = add(1, 2); + println!("{}", c); +} diff --git a/src/test/codegen/debug-column.rs b/src/test/codegen/debug-column.rs new file mode 100644 index 00000000000..f348c48566d --- /dev/null +++ b/src/test/codegen/debug-column.rs @@ -0,0 +1,24 @@ +// Verify that debuginfo column nubmers are 1-based byte offsets. +// +// ignore-windows +// compile-flags: -C debuginfo=2 + +fn main() { + unsafe { + // Column numbers are 1-based. Regression test for #65437. + // CHECK: call void @giraffe(), !dbg [[A:!.*]] + giraffe(); + + // Column numbers use byte offests. Regression test for #67360 + // CHECK: call void @turtle(), !dbg [[B:!.*]] +/* ż */ turtle(); + + // CHECK: [[A]] = !DILocation(line: 10, column: 9, + // CHECK: [[B]] = !DILocation(line: 14, column: 10, + } +} + +extern { + fn giraffe(); + fn turtle(); +} diff --git a/src/test/codegen/enum-discriminant-value.rs b/src/test/codegen/enum-discriminant-value.rs new file mode 100644 index 00000000000..f9da987765f --- /dev/null +++ b/src/test/codegen/enum-discriminant-value.rs @@ -0,0 +1,27 @@ +// Verify that DIEnumerator uses isUnsigned flag when appropriate. +// +// compile-flags: -g -C no-prepopulate-passes + +#[repr(i64)] +pub enum I64 { + I64Min = std::i64::MIN, + I64Max = std::i64::MAX, +} + +#[repr(u64)] +pub enum U64 { + U64Min = std::u64::MIN, + U64Max = std::u64::MAX, +} + +fn main() { + let _a = I64::I64Min; + let _b = I64::I64Max; + let _c = U64::U64Min; + let _d = U64::U64Max; +} + +// CHECK: !DIEnumerator(name: "I64Min", value: -9223372036854775808) +// CHECK: !DIEnumerator(name: "I64Max", value: 9223372036854775807) +// CHECK: !DIEnumerator(name: "U64Min", value: 0, isUnsigned: true) +// CHECK: !DIEnumerator(name: "U64Max", value: 18446744073709551615, isUnsigned: true) diff --git a/src/test/codegen/issue-56927.rs b/src/test/codegen/issue-56927.rs index 0544ff86aac..d502673e2f8 100644 --- a/src/test/codegen/issue-56927.rs +++ b/src/test/codegen/issue-56927.rs @@ -23,7 +23,7 @@ pub fn test1(s: &mut S) { // CHECK-LABEL: @test2 // CHECK: store i32 4, i32* %{{.+}}, align 4 -#[allow(const_err)] +#[allow(unconditional_panic)] #[no_mangle] pub fn test2(s: &mut S) { s.arr[usize::MAX / 4 + 1] = 4; diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs index 52ffb97a5b2..4724dc3c3e5 100644 --- a/src/test/codegen/remap_path_prefix/main.rs +++ b/src/test/codegen/remap_path_prefix/main.rs @@ -12,7 +12,7 @@ mod aux_mod; include!("aux_mod.rs"); // Here we check that the expansion of the file!() macro is mapped. -// CHECK: @0 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>, align 1 +// CHECK: @alloc1 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }>, align 1 pub static FILE_PATH: &'static str = file!(); fn main() { diff --git a/src/test/codegen/sanitizer-recover.rs b/src/test/codegen/sanitizer-recover.rs index 9a583725b0b..05b4ab5653c 100644 --- a/src/test/codegen/sanitizer-recover.rs +++ b/src/test/codegen/sanitizer-recover.rs @@ -14,8 +14,8 @@ //[MSAN-RECOVER-LTO] compile-flags: -Zsanitizer=memory -Zsanitizer-recover=memory -C lto=fat // // MSAN-NOT: @__msan_keep_going -// MSAN-RECOVER: @__msan_keep_going = weak_odr {{.*}} constant i32 1 -// MSAN-RECOVER-LTO: @__msan_keep_going = weak_odr {{.*}} constant i32 1 +// MSAN-RECOVER: @__msan_keep_going = weak_odr {{.*}}constant i32 1 +// MSAN-RECOVER-LTO: @__msan_keep_going = weak_odr {{.*}}constant i32 1 // ASAN-LABEL: define i32 @penguin( // ASAN: call void @__asan_report_load4(i64 %0) diff --git a/src/test/codegen/try-panic-abort.rs b/src/test/codegen/try-panic-abort.rs new file mode 100644 index 00000000000..166d2bb9942 --- /dev/null +++ b/src/test/codegen/try-panic-abort.rs @@ -0,0 +1,20 @@ +// compile-flags: -C panic=abort -O + +#![crate_type = "lib"] +#![feature(unwind_attributes, core_intrinsics)] + +extern "C" { + #[unwind(allow)] + fn bar(data: *mut u8); +} +extern "Rust" { + fn catch(data: *mut u8, exception: *mut u8); +} + +// CHECK-LABEL: @foo +#[no_mangle] +pub unsafe fn foo() -> i32 { + // CHECK: call void @bar + // CHECK: ret i32 0 + std::intrinsics::r#try(|x| bar(x), 0 as *mut u8, |x, y| catch(x, y)) +} diff --git a/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs b/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs index abe34a39caf..3e5cdad7ab9 100644 --- a/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs +++ b/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs @@ -11,5 +11,3 @@ use core::panic::PanicInfo; fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} -#[lang = "eh_unwind_resume"] -fn eh_unwind_resume() {} diff --git a/src/test/compile-fail/chalkify/chalk_initial_program.rs b/src/test/compile-fail/chalkify/chalk_initial_program.rs deleted file mode 100644 index df25bad622b..00000000000 --- a/src/test/compile-fail/chalkify/chalk_initial_program.rs +++ /dev/null @@ -1,16 +0,0 @@ -// compile-flags: -Z chalk - -trait Foo { } - -impl Foo for i32 { } - -impl Foo for u32 { } - -fn gimme() { } - -// Note: this also tests that `std::process::Termination` is implemented for `()`. -fn main() { - gimme::(); - gimme::(); - gimme::(); //~ERROR the trait bound `f32: Foo` is not satisfied -} diff --git a/src/test/compile-fail/chalkify/generic_impls.rs b/src/test/compile-fail/chalkify/generic_impls.rs deleted file mode 100644 index d70c6f8055d..00000000000 --- a/src/test/compile-fail/chalkify/generic_impls.rs +++ /dev/null @@ -1,18 +0,0 @@ -// compile-flags: -Z chalk - -trait Foo { } - -impl Foo for (T, u32) { } - -fn gimme() { } - -fn foo() { - gimme::<(T, u32)>(); - gimme::<(Option, u32)>(); - gimme::<(Option, f32)>(); //~ ERROR -} - -fn main() { - gimme::<(i32, u32)>(); - gimme::<(i32, f32)>(); //~ ERROR -} diff --git a/src/test/compile-fail/chalkify/impl_wf.rs b/src/test/compile-fail/chalkify/impl_wf.rs deleted file mode 100644 index 6bb4cf86e79..00000000000 --- a/src/test/compile-fail/chalkify/impl_wf.rs +++ /dev/null @@ -1,39 +0,0 @@ -// compile-flags: -Z chalk - -trait Foo: Sized { } - -trait Bar { - type Item: Foo; -} - -impl Foo for i32 { } - -impl Foo for str { } -//~^ ERROR the size for values of type `str` cannot be known at compilation time - -// Implicit `T: Sized` bound. -impl Foo for Option { } - -impl Bar for () { - type Item = i32; -} - -impl Bar for Option { - type Item = Option; -} - -impl Bar for f32 { -//~^ ERROR the trait bound `f32: Foo` is not satisfied - type Item = f32; - //~^ ERROR the trait bound `f32: Foo` is not satisfied -} - -trait Baz where U: Foo { } - -impl Baz for i32 { } - -impl Baz for f32 { } -//~^ ERROR the trait bound `f32: Foo` is not satisfied - -fn main() { -} diff --git a/src/test/compile-fail/chalkify/recursive_where_clause_on_type.rs b/src/test/compile-fail/chalkify/recursive_where_clause_on_type.rs deleted file mode 100644 index 861f86e6165..00000000000 --- a/src/test/compile-fail/chalkify/recursive_where_clause_on_type.rs +++ /dev/null @@ -1,28 +0,0 @@ -// compile-flags: -Z chalk - -#![feature(trivial_bounds)] - -trait Bar { - fn foo(); -} -trait Foo: Bar { } - -struct S where S: Foo; - -impl Foo for S { -} - -fn bar() { - T::foo(); -} - -fn foo() { - bar::() -} - -fn main() { - // For some reason, the error is duplicated... - - foo::() //~ ERROR the type `S` is not well-formed (chalk) - //~^ ERROR the type `S` is not well-formed (chalk) -} diff --git a/src/test/compile-fail/chalkify/type_wf.rs b/src/test/compile-fail/chalkify/type_wf.rs deleted file mode 100644 index d1aa975ddc2..00000000000 --- a/src/test/compile-fail/chalkify/type_wf.rs +++ /dev/null @@ -1,24 +0,0 @@ -// compile-flags: -Z chalk - -trait Foo { } - -struct S { - x: T, -} - -impl Foo for i32 { } -impl Foo for Option { } - -fn main() { - let s = S { - x: 5, - }; - - let s = S { //~ ERROR the trait bound `{float}: Foo` is not satisfied - x: 5.0, - }; - - let s = S { - x: Some(5.0), - }; -} diff --git a/src/test/compile-fail/consts/const-err3.rs b/src/test/compile-fail/consts/const-err3.rs deleted file mode 100644 index fc10824f0c0..00000000000 --- a/src/test/compile-fail/consts/const-err3.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![feature(rustc_attrs)] -#![deny(const_err)] - -fn black_box(_: T) { - unimplemented!() -} - -fn main() { - let b = 200u8 + 200u8 + 200u8; - //~^ ERROR const_err - let c = 200u8 * 4; - //~^ ERROR const_err - let d = 42u8 - (42u8 + 1); - //~^ ERROR const_err - let _e = [5u8][1]; - //~^ ERROR const_err - black_box(b); - black_box(c); - black_box(d); -} diff --git a/src/test/debuginfo/empty-string.rs b/src/test/debuginfo/empty-string.rs index 8c5f67a6604..bc4fac3183c 100644 --- a/src/test/debuginfo/empty-string.rs +++ b/src/test/debuginfo/empty-string.rs @@ -2,6 +2,7 @@ // ignore-android: FIXME(#10381) // compile-flags:-g // min-gdb-version: 7.7 +// ignore-gdb-version: 7.11.90 - 8.0.9 // min-lldb-version: 310 // === GDB TESTS =================================================================================== diff --git a/src/test/debuginfo/no-debug-attribute.rs b/src/test/debuginfo/no-debug-attribute.rs deleted file mode 100644 index 198aa2582ae..00000000000 --- a/src/test/debuginfo/no-debug-attribute.rs +++ /dev/null @@ -1,38 +0,0 @@ -// ignore-lldb - -// compile-flags:-g - -// gdb-command:run - -// gdb-command:info locals -// gdb-check:No locals. -// gdb-command:continue - -// gdb-command:info locals -// gdb-check:abc = 10 -// gdb-command:continue - -#![allow(unused_variables)] -#![feature(no_debug)] -#![feature(omit_gdb_pretty_printer_section)] -#![omit_gdb_pretty_printer_section] -#![no_sw_trace] - -#[inline(never)] -fn id(x: T) -> T {x} - -fn function_with_debuginfo() { - let abc = 10_usize; - id(abc); // #break -} - -#[no_debug] -fn function_without_debuginfo() { - let abc = -57i32; - id(abc); // #break -} - -fn main() { - function_without_debuginfo(); - function_with_debuginfo(); -} diff --git a/src/test/incremental/change_symbol_export_status.rs b/src/test/incremental/change_symbol_export_status.rs index 020e697030d..4d25b45cf56 100644 --- a/src/test/incremental/change_symbol_export_status.rs +++ b/src/test/incremental/change_symbol_export_status.rs @@ -2,11 +2,9 @@ // compile-flags: -Zquery-dep-graph #![feature(rustc_attrs)] -#![allow(private_no_mangle_fns)] - -#![rustc_partition_codegened(module="change_symbol_export_status-mod1", cfg="rpass2")] -#![rustc_partition_reused(module="change_symbol_export_status-mod2", cfg="rpass2")] #![no_sw_trace] +#![rustc_partition_codegened(module = "change_symbol_export_status-mod1", cfg = "rpass2")] +#![rustc_partition_reused(module = "change_symbol_export_status-mod2", cfg = "rpass2")] // This test case makes sure that a change in symbol visibility is detected by // our dependency tracking. We do this by changing a module's visibility to diff --git a/src/test/incremental/const-generics/issue-68477.rs b/src/test/incremental/const-generics/issue-68477.rs new file mode 100644 index 00000000000..925931bc4a6 --- /dev/null +++ b/src/test/incremental/const-generics/issue-68477.rs @@ -0,0 +1,23 @@ +// edition:2018 +// revisions:rpass1 +#![feature(const_generics)] + +const FOO: usize = 1; + +struct Container { + val: std::marker::PhantomData, + blah: [(); FOO] +} + +async fn dummy() {} + +async fn foo() { + let a: Container<&'static ()>; + dummy().await; +} + +fn is_send(_: T) {} + +fn main() { + is_send(foo()); +} diff --git a/src/test/incremental/cyclic-trait-hierarchy.rs b/src/test/incremental/cyclic-trait-hierarchy.rs index 27287d06d54..03bb5eea765 100644 --- a/src/test/incremental/cyclic-trait-hierarchy.rs +++ b/src/test/incremental/cyclic-trait-hierarchy.rs @@ -1,4 +1,4 @@ -// Adapated from rust-lang/rust#58813 +// Adapted from rust-lang/rust#58813 // revisions: rpass1 cfail2 diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs index 50d3657d417..87f108abadd 100644 --- a/src/test/incremental/hashes/call_expressions.rs +++ b/src/test/incremental/hashes/call_expressions.rs @@ -25,7 +25,7 @@ pub fn change_callee_function() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_callee_function() { callee2(1, 2) @@ -40,7 +40,7 @@ pub fn change_argument_function() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_argument_function() { callee1(1, 3) @@ -55,10 +55,10 @@ mod change_callee_indirectly_function { #[cfg(not(cfail1))] use super::callee2 as callee; - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_dirty(label="hir_owner_items", cfg="cfail2")] + #[rustc_clean(label="hir_owner_items", cfg="cfail3")] pub fn change_callee_indirectly_function() { @@ -81,7 +81,7 @@ pub fn change_callee_method() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_callee_method() { let s = Struct; @@ -98,7 +98,7 @@ pub fn change_argument_method() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_argument_method() { let s = Struct; @@ -115,7 +115,7 @@ pub fn change_ufcs_callee_method() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_ufcs_callee_method() { let s = Struct; @@ -132,7 +132,7 @@ pub fn change_argument_method_ufcs() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_argument_method_ufcs() { let s = Struct; @@ -149,10 +149,10 @@ pub fn change_to_ufcs() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] -// One might think this would be expanded in the HirBody/Mir, but it actually -// results in slightly different Hir/Mir. +// One might think this would be expanded in the hir_owner_items/Mir, but it actually +// results in slightly different hir_owner/Mir. pub fn change_to_ufcs() { let s = Struct; Struct::method1(&s, 'x', true); @@ -171,7 +171,7 @@ pub mod change_ufcs_callee_indirectly { #[cfg(not(cfail1))] use super::Struct2 as Struct; - #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] diff --git a/src/test/incremental/hashes/closure_expressions.rs b/src/test/incremental/hashes/closure_expressions.rs index b5299d53cad..cd539aedcfe 100644 --- a/src/test/incremental/hashes/closure_expressions.rs +++ b/src/test/incremental/hashes/closure_expressions.rs @@ -22,7 +22,7 @@ pub fn change_closure_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn change_closure_body() { let _ = || 3u32; @@ -38,7 +38,7 @@ pub fn add_parameter() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_parameter() { let x = 0u32; @@ -54,7 +54,7 @@ pub fn change_parameter_pattern() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_parameter_pattern() { let _ = |(x,): (u32,)| x; @@ -69,7 +69,7 @@ pub fn add_move() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_move() { let _ = move || 1; @@ -85,8 +85,8 @@ pub fn add_type_ascription_to_parameter() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, typeck_tables_of")] -#[rustc_clean(cfg="cfail3")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner_items, typeck_tables_of")] +#[rustc_clean(cfg = "cfail3")] pub fn add_type_ascription_to_parameter() { let closure = |x: u32| x + 1u32; let _: u32 = closure(1); @@ -102,7 +102,7 @@ pub fn change_parameter_type() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_parameter_type() { let closure = |x: u16| (x as u64) + 1; diff --git a/src/test/incremental/hashes/consts.rs b/src/test/incremental/hashes/consts.rs index 3d2eed89636..8f77bb24f87 100644 --- a/src/test/incremental/hashes/consts.rs +++ b/src/test/incremental/hashes/consts.rs @@ -19,7 +19,7 @@ const CONST_VISIBILITY: u8 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub const CONST_VISIBILITY: u8 = 0; @@ -29,7 +29,7 @@ pub const CONST_VISIBILITY: u8 = 0; const CONST_CHANGE_TYPE_1: i32 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_1: u32 = 0; @@ -39,13 +39,13 @@ const CONST_CHANGE_TYPE_1: u32 = 0; const CONST_CHANGE_TYPE_2: Option = None; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_2: Option = None; // Change value between simple literals -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_1: i16 = { #[cfg(cfail1)] @@ -57,7 +57,7 @@ const CONST_CHANGE_VALUE_1: i16 = { // Change value between expressions -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_2: i16 = { #[cfg(cfail1)] @@ -67,7 +67,7 @@ const CONST_CHANGE_VALUE_2: i16 = { { 1 + 2 } }; -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_3: i16 = { #[cfg(cfail1)] @@ -77,7 +77,7 @@ const CONST_CHANGE_VALUE_3: i16 = { { 2 * 3 } }; -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_VALUE_4: i16 = { #[cfg(cfail1)] @@ -99,11 +99,11 @@ mod const_change_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as Type; - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_INDIRECTLY_1: Type = Type; - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] const CONST_CHANGE_TYPE_INDIRECTLY_2: Option = None; } diff --git a/src/test/incremental/hashes/enum_constructors.rs b/src/test/incremental/hashes/enum_constructors.rs index 926f7b2dfe7..74d0787c662 100644 --- a/src/test/incremental/hashes/enum_constructors.rs +++ b/src/test/incremental/hashes/enum_constructors.rs @@ -35,7 +35,7 @@ pub fn change_field_value_struct_like() -> Enum { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_field_value_struct_like() -> Enum { Enum::Struct { @@ -58,7 +58,7 @@ pub fn change_field_order_struct_like() -> Enum { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] // FIXME(michaelwoerister):Interesting. I would have thought that that changes the MIR. And it // would if it were not all constants @@ -97,7 +97,7 @@ pub fn change_constructor_path_struct_like() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_path_struct_like() { let _ = Enum2::Struct { @@ -120,7 +120,7 @@ pub fn change_constructor_variant_struct_like() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_variant_struct_like() { let _ = Enum2::Struct2 { @@ -140,7 +140,7 @@ pub mod change_constructor_path_indirectly_struct_like { #[rustc_clean( cfg="cfail2", - except="fn_sig,Hir,HirBody,optimized_mir,mir_built,\ + except="fn_sig,hir_owner,hir_owner_items,optimized_mir,mir_built,\ typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] @@ -162,7 +162,7 @@ pub mod change_constructor_variant_indirectly_struct_like { #[cfg(not(cfail1))] use super::Enum2::Struct2 as Variant; - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built")] + #[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn function() -> Enum2 { Variant { @@ -181,7 +181,7 @@ pub fn change_field_value_tuple_like() -> Enum { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_field_value_tuple_like() -> Enum { Enum::Tuple(0, 1, 3) @@ -198,7 +198,7 @@ pub fn change_constructor_path_tuple_like() { #[cfg(not(cfail1))] #[rustc_clean( cfg="cfail2", - except="HirBody,optimized_mir,mir_built,typeck_tables_of" + except="hir_owner_items,optimized_mir,mir_built,typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_path_tuple_like() { @@ -216,7 +216,7 @@ pub fn change_constructor_variant_tuple_like() { #[cfg(not(cfail1))] #[rustc_clean( cfg="cfail2", - except="HirBody,optimized_mir,mir_built,typeck_tables_of" + except="hir_owner_items,optimized_mir,mir_built,typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_variant_tuple_like() { @@ -233,7 +233,7 @@ pub mod change_constructor_path_indirectly_tuple_like { #[rustc_clean( cfg="cfail2", - except="fn_sig,Hir,HirBody,optimized_mir,mir_built,\ + except="fn_sig,hir_owner,hir_owner_items,optimized_mir,mir_built,\ typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] @@ -252,7 +252,7 @@ pub mod change_constructor_variant_indirectly_tuple_like { #[cfg(not(cfail1))] use super::Enum2::Tuple2 as Variant; - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn function() -> Enum2 { Variant(0, 1, 2) @@ -279,7 +279,7 @@ pub fn change_constructor_path_c_like() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_path_c_like() { let _ = Clike2::B; @@ -294,7 +294,7 @@ pub fn change_constructor_variant_c_like() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_variant_c_like() { let _ = Clike::C; @@ -310,7 +310,7 @@ pub mod change_constructor_path_indirectly_c_like { #[rustc_clean( cfg="cfail2", - except="fn_sig,Hir,HirBody,optimized_mir,mir_built,\ + except="fn_sig,hir_owner,hir_owner_items,optimized_mir,mir_built,\ typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] @@ -329,7 +329,7 @@ pub mod change_constructor_variant_indirectly_c_like { #[cfg(not(cfail1))] use super::Clike::B as Variant; - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built")] + #[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn function() -> Clike { Variant diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index 7256c1aa153..7be15b4bb15 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -26,7 +26,7 @@ enum EnumVisibility { A } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub enum EnumVisibility { A @@ -42,7 +42,7 @@ enum EnumChangeNameCStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumChangeNameCStyleVariant { Variant1, @@ -59,7 +59,7 @@ enum EnumChangeNameTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumChangeNameTupleStyleVariant { Variant1, @@ -76,7 +76,7 @@ enum EnumChangeNameStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumChangeNameStructStyleVariant { Variant1, @@ -93,7 +93,7 @@ enum EnumChangeValueCStyleVariant0 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] enum EnumChangeValueCStyleVariant0 { Variant1, @@ -109,7 +109,7 @@ enum EnumChangeValueCStyleVariant1 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumChangeValueCStyleVariant1 { Variant1, @@ -125,7 +125,7 @@ enum EnumAddCStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddCStyleVariant { Variant1, @@ -142,7 +142,7 @@ enum EnumRemoveCStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumRemoveCStyleVariant { Variant1, @@ -157,7 +157,7 @@ enum EnumAddTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddTupleStyleVariant { Variant1, @@ -174,7 +174,7 @@ enum EnumRemoveTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumRemoveTupleStyleVariant { Variant1, @@ -189,7 +189,7 @@ enum EnumAddStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddStructStyleVariant { Variant1, @@ -206,7 +206,7 @@ enum EnumRemoveStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumRemoveStructStyleVariant { Variant1, @@ -221,7 +221,7 @@ enum EnumChangeFieldTypeTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] enum EnumChangeFieldTypeTupleStyleVariant { Variant1(u32, @@ -238,7 +238,7 @@ enum EnumChangeFieldTypeStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] enum EnumChangeFieldTypeStructStyleVariant { Variant1, @@ -257,7 +257,7 @@ enum EnumChangeFieldNameStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumChangeFieldNameStructStyleVariant { Variant1 { a: u32, c: u32 }, @@ -272,7 +272,7 @@ enum EnumChangeOrderTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] enum EnumChangeOrderTupleStyleVariant { Variant1( @@ -289,7 +289,7 @@ enum EnumChangeFieldOrderStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumChangeFieldOrderStructStyleVariant { Variant1 { b: f32, a: u32 }, @@ -304,7 +304,7 @@ enum EnumAddFieldTupleStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddFieldTupleStyleVariant { Variant1(u32, u32, u32), @@ -319,7 +319,7 @@ enum EnumAddFieldStructStyleVariant { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddFieldStructStyleVariant { Variant1 { a: u32, b: u32, c: u32 }, @@ -335,7 +335,7 @@ enum EnumAddMustUse { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] #[must_use] enum EnumAddMustUse { @@ -353,7 +353,7 @@ enum EnumAddReprC { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] #[repr(C)] enum EnumAddReprC { @@ -531,7 +531,7 @@ enum EnumSwapUsageTypeParameters { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] enum EnumSwapUsageTypeParameters { Variant1 { @@ -552,7 +552,7 @@ enum EnumSwapUsageLifetimeParameters<'a, 'b> { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] enum EnumSwapUsageLifetimeParameters<'a, 'b> { Variant1 { @@ -577,7 +577,7 @@ mod change_field_type_indirectly_tuple_style { #[cfg(not(cfail1))] use super::ReferencedType2 as FieldType; - #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] enum TupleStyle { Variant1( @@ -595,7 +595,7 @@ mod change_field_type_indirectly_struct_style { #[cfg(not(cfail1))] use super::ReferencedType2 as FieldType; - #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] enum StructStyle { Variant1 { @@ -618,7 +618,7 @@ mod change_trait_bound_indirectly { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,predicates_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,predicates_of")] #[rustc_clean(cfg="cfail3")] enum Enum { Variant1(T) @@ -634,7 +634,7 @@ mod change_trait_bound_indirectly_where { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,predicates_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,predicates_of")] #[rustc_clean(cfg="cfail3")] enum Enum where T: Trait { Variant1(T) diff --git a/src/test/incremental/hashes/exported_vs_not.rs b/src/test/incremental/hashes/exported_vs_not.rs index ef275cabeaf..b546930ea8f 100644 --- a/src/test/incremental/hashes/exported_vs_not.rs +++ b/src/test/incremental/hashes/exported_vs_not.rs @@ -7,8 +7,8 @@ #![crate_type="rlib"] // Case 1: The function body is not exported to metadata. If the body changes, -// the hash of the HirBody node should change, but not the hash of -// either the Hir or the Metadata node. +// the hash of the hir_owner_items node should change, but not the hash of +// either the hir_owner or the Metadata node. #[cfg(cfail1)] pub fn body_not_exported_to_metadata() -> u32 { @@ -16,7 +16,7 @@ pub fn body_not_exported_to_metadata() -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn body_not_exported_to_metadata() -> u32 { 2 @@ -25,7 +25,7 @@ pub fn body_not_exported_to_metadata() -> u32 { // Case 2: The function body *is* exported to metadata because the function is -// marked as #[inline]. Only the hash of the Hir depnode should be +// marked as #[inline]. Only the hash of the hir_owner depnode should be // unaffected by a change to the body. #[cfg(cfail1)] @@ -35,7 +35,7 @@ pub fn body_exported_to_metadata_because_of_inline() -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] #[inline] pub fn body_exported_to_metadata_because_of_inline() -> u32 { @@ -45,7 +45,7 @@ pub fn body_exported_to_metadata_because_of_inline() -> u32 { // Case 2: The function body *is* exported to metadata because the function is -// generic. Only the hash of the Hir depnode should be +// generic. Only the hash of the hir_owner depnode should be // unaffected by a change to the body. #[cfg(cfail1)] @@ -55,7 +55,7 @@ pub fn body_exported_to_metadata_because_of_generic() -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] #[inline] pub fn body_exported_to_metadata_because_of_generic() -> u32 { diff --git a/src/test/incremental/hashes/for_loops.rs b/src/test/incremental/hashes/for_loops.rs index 26eee9e9f74..fd8cdc9ed1b 100644 --- a/src/test/incremental/hashes/for_loops.rs +++ b/src/test/incremental/hashes/for_loops.rs @@ -26,7 +26,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; @@ -49,7 +49,7 @@ pub fn change_iteration_variable_name() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_iteration_variable_name() { let mut _x = 0; @@ -72,7 +72,7 @@ pub fn change_iteration_variable_pattern() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_iteration_variable_pattern() { let mut _x = 0; @@ -95,7 +95,7 @@ pub fn change_iterable() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, promoted_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, promoted_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_iterable() { let mut _x = 0; @@ -117,7 +117,7 @@ pub fn add_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_break() { let mut _x = 0; @@ -140,7 +140,7 @@ pub fn add_loop_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label() { let mut _x = 0; @@ -163,7 +163,7 @@ pub fn add_loop_label_to_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label_to_break() { let mut _x = 0; @@ -188,7 +188,7 @@ pub fn change_break_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_break_label() { let mut _x = 0; @@ -213,7 +213,7 @@ pub fn add_loop_label_to_continue() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label_to_continue() { let mut _x = 0; @@ -238,7 +238,7 @@ pub fn change_continue_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_continue_label() { let mut _x = 0; @@ -263,7 +263,7 @@ pub fn change_continue_to_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs index 7e5ad3c73bd..7feadeb44a5 100644 --- a/src/test/incremental/hashes/function_interfaces.rs +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -9,199 +9,197 @@ // revisions: cfail1 cfail2 cfail3 // compile-flags: -Z query-dep-graph -Zincremental-ignore-spans - #![allow(warnings)] #![feature(linkage)] #![feature(rustc_attrs)] #![crate_type = "rlib"] #![no_sw_trace] - // Add Parameter --------------------------------------------------------------- #[cfg(cfail1)] pub fn add_parameter() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] +#[rustc_clean( + cfg = "cfail2", + except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig" +)] #[rustc_clean(cfg = "cfail3")] pub fn add_parameter(p: i32) {} - // Add Return Type ------------------------------------------------------------- #[cfg(cfail1)] pub fn add_return_type() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")] #[rustc_clean(cfg = "cfail3")] pub fn add_return_type() -> () {} - // Change Parameter Type ------------------------------------------------------- #[cfg(cfail1)] pub fn type_of_parameter(p: i32) {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] +#[rustc_clean( + cfg = "cfail2", + except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig" +)] #[rustc_clean(cfg = "cfail3")] pub fn type_of_parameter(p: i64) {} - // Change Parameter Type Reference --------------------------------------------- #[cfg(cfail1)] pub fn type_of_parameter_ref(p: &i32) {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] +#[rustc_clean( + cfg = "cfail2", + except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig" +)] #[rustc_clean(cfg = "cfail3")] pub fn type_of_parameter_ref(p: &mut i32) {} - // Change Parameter Order ------------------------------------------------------ #[cfg(cfail1)] pub fn order_of_parameters(p1: i32, p2: i64) {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] +#[rustc_clean( + cfg = "cfail2", + except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig" +)] #[rustc_clean(cfg = "cfail3")] pub fn order_of_parameters(p2: i64, p1: i32) {} - // Unsafe ---------------------------------------------------------------------- #[cfg(cfail1)] pub fn make_unsafe() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] +#[rustc_clean( + cfg = "cfail2", + except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig" +)] #[rustc_clean(cfg = "cfail3")] pub unsafe fn make_unsafe() {} - // Extern ---------------------------------------------------------------------- #[cfg(cfail1)] pub fn make_extern() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, typeck_tables_of, fn_sig")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub extern "C" fn make_extern() {} - // Type Parameter -------------------------------------------------------------- #[cfg(cfail1)] pub fn type_parameter() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, generics_of, type_of, predicates_of")] +#[rustc_clean( + cfg = "cfail2", + except = "hir_owner, hir_owner_items, generics_of, type_of, predicates_of" +)] #[rustc_clean(cfg = "cfail3")] pub fn type_parameter() {} - // Lifetime Parameter ---------------------------------------------------------- #[cfg(cfail1)] pub fn lifetime_parameter() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, generics_of")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, generics_of")] #[rustc_clean(cfg = "cfail3")] pub fn lifetime_parameter<'a>() {} - // Trait Bound ----------------------------------------------------------------- #[cfg(cfail1)] pub fn trait_bound() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn trait_bound() {} - // Builtin Bound --------------------------------------------------------------- #[cfg(cfail1)] pub fn builtin_bound() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn builtin_bound() {} - // Lifetime Bound -------------------------------------------------------------- #[cfg(cfail1)] pub fn lifetime_bound<'a, T>() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, generics_of, type_of, predicates_of")] +#[rustc_clean( + cfg = "cfail2", + except = "hir_owner, hir_owner_items, generics_of, type_of, predicates_of" +)] #[rustc_clean(cfg = "cfail3")] pub fn lifetime_bound<'a, T: 'a>() {} - // Second Trait Bound ---------------------------------------------------------- #[cfg(cfail1)] pub fn second_trait_bound() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn second_trait_bound() {} - // Second Builtin Bound -------------------------------------------------------- #[cfg(cfail1)] pub fn second_builtin_bound() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn second_builtin_bound() {} - // Second Lifetime Bound ------------------------------------------------------- #[cfg(cfail1)] pub fn second_lifetime_bound<'a, 'b, T: 'a>() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, generics_of, type_of, predicates_of")] +#[rustc_clean( + cfg = "cfail2", + except = "hir_owner, hir_owner_items, generics_of, type_of, predicates_of" +)] #[rustc_clean(cfg = "cfail3")] pub fn second_lifetime_bound<'a, 'b, T: 'a + 'b>() {} - // Inline ---------------------------------------------------------------------- #[cfg(cfail1)] pub fn inline() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")] #[rustc_clean(cfg = "cfail3")] #[inline] pub fn inline() {} - // Inline Never ---------------------------------------------------------------- #[cfg(cfail1)] @@ -209,36 +207,33 @@ pub fn inline() {} pub fn inline_never() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")] #[rustc_clean(cfg = "cfail3")] #[inline(never)] pub fn inline_never() {} - // No Mangle ------------------------------------------------------------------- #[cfg(cfail1)] pub fn no_mangle() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")] #[rustc_clean(cfg = "cfail3")] #[no_mangle] pub fn no_mangle() {} - // Linkage --------------------------------------------------------------------- #[cfg(cfail1)] pub fn linkage() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items")] #[rustc_clean(cfg = "cfail3")] #[linkage = "weak_odr"] pub fn linkage() {} - // Return Impl Trait ----------------------------------------------------------- #[cfg(cfail1)] @@ -247,13 +242,12 @@ pub fn return_impl_trait() -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, typeck_tables_of, fn_sig")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub fn return_impl_trait() -> impl Clone { 0 } - // Change Return Impl Trait ---------------------------------------------------- #[cfg(cfail1)] @@ -268,7 +262,6 @@ pub fn change_return_impl_trait() -> impl Copy { 0u32 } - // Change Return Type Indirectly ----------------------------------------------- pub struct ReferencedType1; @@ -280,15 +273,16 @@ pub mod change_return_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as ReturnType; - #[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] + #[rustc_clean( + cfg = "cfail2", + except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig" + )] #[rustc_clean(cfg = "cfail3")] pub fn indirect_return_type() -> ReturnType { ReturnType {} } } - // Change Parameter Type Indirectly -------------------------------------------- pub mod change_parameter_type_indirectly { @@ -297,13 +291,14 @@ pub mod change_parameter_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as ParameterType; - #[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] + #[rustc_clean( + cfg = "cfail2", + except = "hir_owner, hir_owner_items, mir_built, optimized_mir, typeck_tables_of, fn_sig" + )] #[rustc_clean(cfg = "cfail3")] pub fn indirect_parameter_type(p: ParameterType) {} } - // Change Trait Bound Indirectly ----------------------------------------------- pub trait ReferencedTrait1 {} @@ -315,12 +310,11 @@ pub mod change_trait_bound_indirectly { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")] + #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn indirect_trait_bound(p: T) {} } - // Change Trait Bound Indirectly In Where Clause ------------------------------- pub mod change_trait_bound_indirectly_in_where_clause { @@ -329,7 +323,7 @@ pub mod change_trait_bound_indirectly_in_where_clause { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, predicates_of")] + #[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_items, predicates_of")] #[rustc_clean(cfg = "cfail3")] pub fn indirect_trait_bound_where(p: T) where diff --git a/src/test/incremental/hashes/if_expressions.rs b/src/test/incremental/hashes/if_expressions.rs index 3cd7415a2b9..a85746678ef 100644 --- a/src/test/incremental/hashes/if_expressions.rs +++ b/src/test/incremental/hashes/if_expressions.rs @@ -26,7 +26,7 @@ pub fn change_condition(x: bool) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_condition(x: bool) -> u32 { if !x { @@ -47,7 +47,7 @@ pub fn change_then_branch(x: bool) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_then_branch(x: bool) -> u32 { if x { @@ -70,7 +70,7 @@ pub fn change_else_branch(x: bool) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_else_branch(x: bool) -> u32 { if x { @@ -95,7 +95,7 @@ pub fn add_else_branch(x: bool) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_else_branch(x: bool) -> u32 { let mut ret = 1; @@ -121,7 +121,7 @@ pub fn change_condition_if_let(x: Option) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_condition_if_let(x: Option) -> u32 { if let Some(_) = x { @@ -144,7 +144,7 @@ pub fn change_then_branch_if_let(x: Option) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_then_branch_if_let(x: Option) -> u32 { if let Some(x) = x { @@ -167,7 +167,7 @@ pub fn change_else_branch_if_let(x: Option) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_else_branch_if_let(x: Option) -> u32 { if let Some(x) = x { @@ -192,7 +192,7 @@ pub fn add_else_branch_if_let(x: Option) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_else_branch_if_let(x: Option) -> u32 { let mut ret = 1; diff --git a/src/test/incremental/hashes/indexing_expressions.rs b/src/test/incremental/hashes/indexing_expressions.rs index 08cf19d7760..84c0298918e 100644 --- a/src/test/incremental/hashes/indexing_expressions.rs +++ b/src/test/incremental/hashes/indexing_expressions.rs @@ -20,10 +20,10 @@ fn change_simple_index(slice: &[u32]) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] fn change_simple_index(slice: &[u32]) -> u32 { slice[4] } @@ -37,10 +37,10 @@ fn change_lower_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] fn change_lower_bound(slice: &[u32]) -> &[u32] { &slice[2..5] } @@ -54,10 +54,10 @@ fn change_upper_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] fn change_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..7] } @@ -71,10 +71,10 @@ fn add_lower_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] fn add_lower_bound(slice: &[u32]) -> &[u32] { &slice[3..4] } @@ -88,10 +88,10 @@ fn add_upper_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] fn add_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..7] } @@ -105,10 +105,10 @@ fn change_mutability(slice: &mut [u32]) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] fn change_mutability(slice: &mut [u32]) -> u32 { (&slice[3..5])[0] } @@ -122,10 +122,10 @@ fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { &slice[3..=7] } diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index f77253dafc1..892519b3e96 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -24,7 +24,7 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,associated_item_def_ids")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] impl Foo { #[rustc_clean(cfg="cfail3")] @@ -45,7 +45,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="HirBody,optimized_mir,promoted_mir,mir_built,typeck_tables_of" + except="hir_owner_items,optimized_mir,promoted_mir,mir_built,typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn method_body() { @@ -69,7 +69,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="HirBody,optimized_mir,promoted_mir,mir_built,typeck_tables_of" + except="hir_owner_items,optimized_mir,promoted_mir,mir_built,typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] #[inline] @@ -86,10 +86,10 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="associated_item,Hir,HirBody")] + #[rustc_clean(cfg="cfail2", except="associated_item,hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] fn method_privacy() { } } @@ -101,7 +101,7 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] impl Foo { #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")] @@ -121,7 +121,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="Hir,HirBody,fn_sig,typeck_tables_of,optimized_mir,mir_built" + except="hir_owner,hir_owner_items,fn_sig,typeck_tables_of,optimized_mir,mir_built" )] #[rustc_clean(cfg="cfail3")] pub fn method_selfmutness(&mut self) { } @@ -136,7 +136,7 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,associated_item_def_ids")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] impl Foo { #[rustc_clean(cfg="cfail2")] @@ -161,7 +161,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="Hir,HirBody,fn_sig,typeck_tables_of,optimized_mir,mir_built" + except="hir_owner,hir_owner_items,fn_sig,typeck_tables_of,optimized_mir,mir_built" )] #[rustc_clean(cfg="cfail3")] pub fn add_method_parameter(&self, _: i32) { } @@ -179,7 +179,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built")] + #[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_method_parameter_name(&self, b: i64) { } } @@ -198,7 +198,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="Hir,HirBody,fn_sig,optimized_mir,mir_built,typeck_tables_of")] + except="hir_owner,hir_owner_items,fn_sig,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_method_return_type(&self) -> u8 { 0 } } @@ -215,7 +215,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] #[inline] pub fn make_method_inline(&self) -> u8 { 0 } @@ -233,7 +233,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built")] + #[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_method_parameter_order(&self, b: i64, a: i64) { } } @@ -252,7 +252,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="Hir,HirBody,fn_sig,typeck_tables_of,optimized_mir,mir_built" + except="hir_owner,hir_owner_items,fn_sig,typeck_tables_of,optimized_mir,mir_built" )] #[rustc_clean(cfg="cfail3")] pub unsafe fn make_method_unsafe(&self) { } @@ -270,7 +270,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,fn_sig,typeck_tables_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,fn_sig,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub extern fn make_method_extern(&self) { } } @@ -287,7 +287,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,fn_sig,typeck_tables_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,fn_sig,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub extern "system" fn change_method_calling_convention(&self) { } } @@ -313,7 +313,7 @@ impl Foo { // if we lower generics before the body, then the `HirId` for // things in the body will be affected. So if you start to see // `typeck_tables_of` appear dirty, that might be the cause. -nmatsakis - #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_lifetime_parameter_to_method<'a>(&self) { } } @@ -341,7 +341,7 @@ impl Foo { // appear dirty, that might be the cause. -nmatsakis #[rustc_clean( cfg="cfail2", - except="Hir,HirBody,generics_of,predicates_of,type_of", + except="hir_owner,hir_owner_items,generics_of,predicates_of,type_of", )] #[rustc_clean(cfg="cfail3")] pub fn add_type_parameter_to_method(&self) { } @@ -361,7 +361,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="Hir,HirBody,generics_of,predicates_of,type_of,typeck_tables_of" + except="hir_owner,hir_owner_items,generics_of,predicates_of,type_of" )] #[rustc_clean(cfg="cfail3")] pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b: 'a>(&self) { } @@ -388,7 +388,7 @@ impl Foo { // generics before the body, then the `HirId` for things in the // body will be affected. So if you start to see `typeck_tables_of` // appear dirty, that might be the cause. -nmatsakis - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,generics_of,predicates_of,\ + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,generics_of,predicates_of,\ type_of")] #[rustc_clean(cfg="cfail3")] pub fn add_lifetime_bound_to_type_param_of_method<'a, T: 'a>(&self) { } @@ -415,7 +415,7 @@ impl Foo { // generics before the body, then the `HirId` for things in the // body will be affected. So if you start to see `typeck_tables_of` // appear dirty, that might be the cause. -nmatsakis - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,predicates_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,predicates_of")] #[rustc_clean(cfg="cfail3")] pub fn add_trait_bound_to_type_param_of_method(&self) { } } @@ -432,7 +432,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] #[no_mangle] pub fn add_no_mangle_to_method(&self) { } @@ -449,7 +449,7 @@ impl Bar { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,generics_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,generics_of")] #[rustc_clean(cfg="cfail3")] impl Bar { #[rustc_clean( @@ -469,7 +469,7 @@ impl Bar { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] impl Bar { #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,mir_built,typeck_tables_of")] @@ -486,7 +486,7 @@ impl Bar { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] impl Bar { #[rustc_clean(cfg="cfail2")] @@ -503,7 +503,7 @@ impl Bar { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] impl Bar { #[rustc_clean(cfg="cfail2")] diff --git a/src/test/incremental/hashes/inline_asm.rs b/src/test/incremental/hashes/inline_asm.rs index c50ee73d714..a77123110ae 100644 --- a/src/test/incremental/hashes/inline_asm.rs +++ b/src/test/incremental/hashes/inline_asm.rs @@ -33,7 +33,7 @@ pub fn change_template(a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_template(a: i32) -> i32 { @@ -69,7 +69,7 @@ pub fn change_output(a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_output(a: i32) -> i32 { @@ -105,7 +105,7 @@ pub fn change_input(_a: i32, _b: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_input(_a: i32, _b: i32) -> i32 { @@ -140,7 +140,7 @@ pub fn change_input_constraint(_a: i32, _b: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_input_constraint(_a: i32, _b: i32) -> i32 { @@ -175,7 +175,7 @@ pub fn change_clobber(_a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_clobber(_a: i32) -> i32 { @@ -210,7 +210,7 @@ pub fn change_options(_a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn change_options(_a: i32) -> i32 { diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 654503d0bea..8481f60bfeb 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -23,7 +23,7 @@ pub fn change_name() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir")] + except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_name() { let _y = 2u64; @@ -39,7 +39,7 @@ pub fn add_type() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="hir_owner_items,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn add_type() { let _x: u32 = 2u32; @@ -55,7 +55,7 @@ pub fn change_type() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="hir_owner_items,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_type() { let _x: u8 = 2; @@ -71,7 +71,7 @@ pub fn change_mutability_of_reference_type() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="hir_owner_items,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_reference_type() { let _x: &mut u64; @@ -87,7 +87,7 @@ pub fn change_mutability_of_slot() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="hir_owner_items,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_slot() { let _x: u64 = 0; @@ -103,7 +103,7 @@ pub fn change_simple_binding_to_pattern() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="hir_owner_items,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_simple_binding_to_pattern() { let (_a, _b) = (0u8, 'x'); @@ -119,7 +119,7 @@ pub fn change_name_in_pattern() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir")] + except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_name_in_pattern() { let (_a, _c) = (1u8, 'y'); @@ -135,7 +135,7 @@ pub fn add_ref_in_pattern() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="hir_owner_items,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn add_ref_in_pattern() { let (ref _a, _b) = (1u8, 'y'); @@ -151,7 +151,7 @@ pub fn add_amp_in_pattern() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="hir_owner_items,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn add_amp_in_pattern() { let (&_a, _b) = (&1u8, 'y'); @@ -167,7 +167,7 @@ pub fn change_mutability_of_binding_in_pattern() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="hir_owner_items,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_binding_in_pattern() { let (mut _a, _b) = (99u8, 'q'); @@ -183,7 +183,7 @@ pub fn add_initializer() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,typeck_tables_of,mir_built,optimized_mir")] + except="hir_owner_items,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn add_initializer() { let _x: i16 = 3i16; @@ -199,7 +199,7 @@ pub fn change_initializer() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir")] + except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_initializer() { let _x = 5u16; diff --git a/src/test/incremental/hashes/loop_expressions.rs b/src/test/incremental/hashes/loop_expressions.rs index c1157bd2d16..df47216f5c1 100644 --- a/src/test/incremental/hashes/loop_expressions.rs +++ b/src/test/incremental/hashes/loop_expressions.rs @@ -26,7 +26,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; @@ -48,7 +48,7 @@ pub fn add_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_break() { let mut _x = 0; @@ -71,7 +71,7 @@ pub fn add_loop_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label() { let mut _x = 0; @@ -94,7 +94,7 @@ pub fn add_loop_label_to_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label_to_break() { let mut _x = 0; @@ -119,7 +119,7 @@ pub fn change_break_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_break_label() { let mut _x = 0; @@ -144,7 +144,7 @@ pub fn add_loop_label_to_continue() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label_to_continue() { let mut _x = 0; @@ -169,7 +169,7 @@ pub fn change_continue_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_continue_label() { let mut _x = 0; @@ -194,7 +194,7 @@ pub fn change_continue_to_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/src/test/incremental/hashes/match_expressions.rs b/src/test/incremental/hashes/match_expressions.rs index 840b2222d90..30934c7c1d1 100644 --- a/src/test/incremental/hashes/match_expressions.rs +++ b/src/test/incremental/hashes/match_expressions.rs @@ -26,7 +26,7 @@ pub fn add_arm(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,typeck_tables_of")] + except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_arm(x: u32) -> u32 { match x { @@ -51,7 +51,7 @@ pub fn change_order_of_arms(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir")] + except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_order_of_arms(x: u32) -> u32 { match x { @@ -75,7 +75,7 @@ pub fn add_guard_clause(x: u32, y: bool) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,typeck_tables_of")] + except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_guard_clause(x: u32, y: bool) -> u32 { match x { @@ -99,7 +99,7 @@ pub fn change_guard_clause(x: u32, y: bool) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,typeck_tables_of")] + except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_guard_clause(x: u32, y: bool) -> u32 { match x { @@ -123,7 +123,7 @@ pub fn add_at_binding(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,typeck_tables_of")] + except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_at_binding(x: u32) -> u32 { match x { @@ -147,7 +147,7 @@ pub fn change_name_of_at_binding(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir")] + except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_name_of_at_binding(x: u32) -> u32 { match x { @@ -170,7 +170,7 @@ pub fn change_simple_name_to_pattern(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,typeck_tables_of")] + except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_simple_name_to_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -193,7 +193,7 @@ pub fn change_name_in_pattern(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir")] + except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_name_in_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -216,7 +216,7 @@ pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,typeck_tables_of")] + except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -238,7 +238,7 @@ pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,typeck_tables_of")] + except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -260,7 +260,7 @@ pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", -except="HirBody,mir_built,optimized_mir,typeck_tables_of")] +except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { match (&x, x & 1) { @@ -283,7 +283,7 @@ pub fn change_rhs_of_arm(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir")] + except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_rhs_of_arm(x: u32) -> u32 { match x { @@ -307,7 +307,7 @@ pub fn add_alternative_to_arm(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,typeck_tables_of")] + except="hir_owner_items,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_alternative_to_arm(x: u32) -> u32 { match x { diff --git a/src/test/incremental/hashes/panic_exprs.rs b/src/test/incremental/hashes/panic_exprs.rs index 70b0a5ab78c..b46d1fac124 100644 --- a/src/test/incremental/hashes/panic_exprs.rs +++ b/src/test/incremental/hashes/panic_exprs.rs @@ -18,7 +18,7 @@ // Indexing expression -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn indexing(slice: &[u8]) -> u8 { #[cfg(cfail1)] @@ -33,7 +33,7 @@ pub fn indexing(slice: &[u8]) -> u8 { // Arithmetic overflow plus -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_plus(val: i32) -> i32 { #[cfg(cfail1)] @@ -48,7 +48,7 @@ pub fn arithmetic_overflow_plus(val: i32) -> i32 { // Arithmetic overflow minus -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_minus(val: i32) -> i32 { #[cfg(cfail1)] @@ -63,7 +63,7 @@ pub fn arithmetic_overflow_minus(val: i32) -> i32 { // Arithmetic overflow mult -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_mult(val: i32) -> i32 { #[cfg(cfail1)] @@ -78,7 +78,7 @@ pub fn arithmetic_overflow_mult(val: i32) -> i32 { // Arithmetic overflow negation -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn arithmetic_overflow_negation(val: i32) -> i32 { #[cfg(cfail1)] @@ -93,7 +93,7 @@ pub fn arithmetic_overflow_negation(val: i32) -> i32 { // Division by zero -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn division_by_zero(val: i32) -> i32 { #[cfg(cfail1)] @@ -107,7 +107,7 @@ pub fn division_by_zero(val: i32) -> i32 { } // Division by zero -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn mod_by_zero(val: i32) -> i32 { #[cfg(cfail1)] @@ -122,7 +122,7 @@ pub fn mod_by_zero(val: i32) -> i32 { // shift left -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn shift_left(val: i32, shift: usize) -> i32 { #[cfg(cfail1)] @@ -137,7 +137,7 @@ pub fn shift_left(val: i32, shift: usize) -> i32 { // shift right -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn shift_right(val: i32, shift: usize) -> i32 { #[cfg(cfail1)] diff --git a/src/test/incremental/hashes/statics.rs b/src/test/incremental/hashes/statics.rs index d70ebb08b71..536b7932473 100644 --- a/src/test/incremental/hashes/statics.rs +++ b/src/test/incremental/hashes/statics.rs @@ -21,7 +21,7 @@ static STATIC_VISIBILITY: u8 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub static STATIC_VISIBILITY: u8 = 0; @@ -31,7 +31,7 @@ pub static STATIC_VISIBILITY: u8 = 0; static STATIC_MUTABILITY: u8 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] static mut STATIC_MUTABILITY: u8 = 0; @@ -41,7 +41,7 @@ static mut STATIC_MUTABILITY: u8 = 0; static STATIC_LINKAGE: u8 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] #[linkage="weak_odr"] static STATIC_LINKAGE: u8 = 0; @@ -52,7 +52,7 @@ static STATIC_LINKAGE: u8 = 0; static STATIC_NO_MANGLE: u8 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] #[no_mangle] static STATIC_NO_MANGLE: u8 = 0; @@ -63,7 +63,7 @@ static STATIC_NO_MANGLE: u8 = 0; static STATIC_THREAD_LOCAL: u8 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] #[thread_local] static STATIC_THREAD_LOCAL: u8 = 0; @@ -74,7 +74,7 @@ static STATIC_THREAD_LOCAL: u8 = 0; static STATIC_CHANGE_TYPE_1: i16 = 0; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] static STATIC_CHANGE_TYPE_1: u64 = 0; @@ -84,13 +84,13 @@ static STATIC_CHANGE_TYPE_1: u64 = 0; static STATIC_CHANGE_TYPE_2: Option = None; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] static STATIC_CHANGE_TYPE_2: Option = None; // Change value between simple literals -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] static STATIC_CHANGE_VALUE_1: i16 = { #[cfg(cfail1)] @@ -102,7 +102,7 @@ static STATIC_CHANGE_VALUE_1: i16 = { // Change value between expressions -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] static STATIC_CHANGE_VALUE_2: i16 = { #[cfg(cfail1)] @@ -112,7 +112,7 @@ static STATIC_CHANGE_VALUE_2: i16 = { { 1 + 2 } }; -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] static STATIC_CHANGE_VALUE_3: i16 = { #[cfg(cfail1)] @@ -122,7 +122,7 @@ static STATIC_CHANGE_VALUE_3: i16 = { { 2 * 3 } }; -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] static STATIC_CHANGE_VALUE_4: i16 = { #[cfg(cfail1)] @@ -144,11 +144,11 @@ mod static_change_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as Type; - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] static STATIC_CHANGE_TYPE_INDIRECTLY_1: Type = Type; - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,type_of")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items,type_of")] #[rustc_clean(cfg="cfail3")] static STATIC_CHANGE_TYPE_INDIRECTLY_2: Option = None; } diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs index eac0bf72eea..7cadc4908b4 100644 --- a/src/test/incremental/hashes/struct_constructors.rs +++ b/src/test/incremental/hashes/struct_constructors.rs @@ -32,7 +32,7 @@ pub fn change_field_value_regular_struct() -> RegularStruct { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_field_value_regular_struct() -> RegularStruct { RegularStruct { @@ -55,7 +55,7 @@ pub fn change_field_order_regular_struct() -> RegularStruct { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_field_order_regular_struct() -> RegularStruct { RegularStruct { @@ -83,7 +83,7 @@ pub fn add_field_regular_struct() -> RegularStruct { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_field_regular_struct() -> RegularStruct { let struct1 = RegularStruct { @@ -118,7 +118,7 @@ pub fn change_field_label_regular_struct() -> RegularStruct { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_field_label_regular_struct() -> RegularStruct { let struct1 = RegularStruct { @@ -153,7 +153,7 @@ pub fn change_constructor_path_regular_struct() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_path_regular_struct() { let _ = RegularStruct2 { @@ -174,7 +174,7 @@ pub mod change_constructor_path_indirectly_regular_struct { #[rustc_clean( cfg="cfail2", - except="fn_sig,Hir,HirBody,optimized_mir,mir_built,typeck_tables_of" + except="fn_sig,hir_owner,hir_owner_items,optimized_mir,mir_built,typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn function() -> Struct { @@ -197,7 +197,7 @@ pub fn change_field_value_tuple_struct() -> TupleStruct { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,optimized_mir,mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_field_value_tuple_struct() -> TupleStruct { TupleStruct(0, 1, 3) @@ -214,7 +214,7 @@ pub fn change_constructor_path_tuple_struct() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_path_tuple_struct() { let _ = TupleStruct2(0, 1, 2); @@ -231,7 +231,7 @@ pub mod change_constructor_path_indirectly_tuple_struct { #[rustc_clean( cfg="cfail2", - except="fn_sig,Hir,HirBody,optimized_mir,mir_built,typeck_tables_of" + except="fn_sig,hir_owner,hir_owner_items,optimized_mir,mir_built,typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn function() -> Struct { diff --git a/src/test/incremental/hashes/struct_defs.rs b/src/test/incremental/hashes/struct_defs.rs index e0c56964831..fa08b7ec1ed 100644 --- a/src/test/incremental/hashes/struct_defs.rs +++ b/src/test/incremental/hashes/struct_defs.rs @@ -24,13 +24,13 @@ pub struct LayoutPacked; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_dirty(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -41,13 +41,13 @@ pub struct LayoutPacked; struct LayoutC; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_dirty(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -61,13 +61,13 @@ struct LayoutC; struct TupleStructFieldType(i32); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -84,13 +84,13 @@ struct TupleStructFieldType( struct TupleStructAddField(i32); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_dirty(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -106,13 +106,13 @@ struct TupleStructAddField( struct TupleStructFieldVisibility(char); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_dirty(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -125,13 +125,13 @@ struct TupleStructFieldVisibility(pub char); struct RecordStructFieldType { x: f32 } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -148,13 +148,13 @@ struct RecordStructFieldType { struct RecordStructFieldName { x: f32 } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_dirty(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -167,13 +167,13 @@ struct RecordStructFieldName { y: f32 } struct RecordStructAddField { x: f32 } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_dirty(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -188,13 +188,13 @@ struct RecordStructAddField { struct RecordStructFieldVisibility { x: f32 } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_dirty(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -209,13 +209,13 @@ struct RecordStructFieldVisibility { struct AddLifetimeParameter<'a>(&'a f32, &'a f64); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_dirty(label="type_of", cfg="cfail2")] #[rustc_dirty(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -228,13 +228,13 @@ struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64); struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_dirty(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -247,13 +247,13 @@ struct AddLifetimeParameterBound<'a, 'b: 'a>( struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_dirty(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -269,13 +269,13 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>( struct AddTypeParameter(T1, T1); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_dirty(label="type_of", cfg="cfail2")] #[rustc_dirty(label="generics_of", cfg="cfail2")] #[rustc_dirty(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -293,13 +293,13 @@ struct AddTypeParameter( struct AddTypeParameterBound(T); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_dirty(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -312,13 +312,13 @@ struct AddTypeParameterBound( struct AddTypeParameterBoundWhereClause(T); #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_dirty(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -332,13 +332,13 @@ struct AddTypeParameterBoundWhereClause( // fingerprint is stable (i.e., that there are no random influences like memory // addresses taken into account by the hashing algorithm). // Note: there is no #[cfg(...)], so this is ALWAYS compiled -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="HirBody", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -351,13 +351,13 @@ pub struct EmptyStruct; struct Visibility; #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] -#[rustc_clean(label="HirBody", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -373,13 +373,13 @@ mod tuple_struct_change_field_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as FieldType; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -396,13 +396,13 @@ mod record_struct_change_field_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as FieldType; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_clean(label="predicates_of", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -424,13 +424,13 @@ mod change_trait_bound_indirectly { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_dirty(label="predicates_of", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] @@ -444,13 +444,13 @@ mod change_trait_bound_indirectly_in_where_clause { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_clean(label="type_of", cfg="cfail2")] #[rustc_clean(label="generics_of", cfg="cfail2")] #[rustc_dirty(label="predicates_of", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[rustc_clean(label="type_of", cfg="cfail3")] #[rustc_clean(label="generics_of", cfg="cfail3")] #[rustc_clean(label="predicates_of", cfg="cfail3")] diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index 3006cdccfbb..df41b73f92c 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -25,8 +25,8 @@ trait TraitVisibility { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] pub trait TraitVisibility { } @@ -36,8 +36,8 @@ pub trait TraitVisibility { } trait TraitUnsafety { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] unsafe trait TraitUnsafety { } @@ -48,8 +48,8 @@ trait TraitAddMethod { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] pub trait TraitAddMethod { fn method(); } @@ -63,8 +63,8 @@ trait TraitChangeMethodName { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeMethodName { fn methodChanged(); } @@ -78,11 +78,11 @@ trait TraitAddReturnType { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddReturnType { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method() -> u32; } @@ -95,11 +95,11 @@ trait TraitChangeReturnType { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeReturnType { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method() -> u64; } @@ -112,11 +112,11 @@ trait TraitAddParameterToMethod { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddParameterToMethod { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(a: u32); } @@ -130,18 +130,18 @@ trait TraitChangeMethodParameterName { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeMethodParameterName { // FIXME(#38501) This should preferably always be clean. - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(b: u32); - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_dirty(label="hir_owner_items", cfg="cfail2")] + #[rustc_clean(label="hir_owner_items", cfg="cfail3")] fn with_default(y: i32) {} } @@ -154,11 +154,11 @@ trait TraitChangeMethodParameterType { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeMethodParameterType { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(a: i64); } @@ -171,11 +171,11 @@ trait TraitChangeMethodParameterTypeRef { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeMethodParameterTypeRef { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(a: &mut i32); } @@ -188,11 +188,11 @@ trait TraitChangeMethodParametersOrder { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeMethodParametersOrder { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(b: i64, a: i32); } @@ -205,11 +205,11 @@ trait TraitAddMethodAutoImplementation { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddMethodAutoImplementation { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method() { } } @@ -223,8 +223,8 @@ trait TraitChangeOrderOfMethods { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeOrderOfMethods { fn method1(); fn method0(); @@ -239,11 +239,11 @@ trait TraitChangeModeSelfRefToMut { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeModeSelfRefToMut { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(&mut self); } @@ -255,13 +255,13 @@ trait TraitChangeModeSelfOwnToMut: Sized { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeModeSelfOwnToMut: Sized { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_dirty(label="hir_owner_items", cfg="cfail2")] + #[rustc_clean(label="hir_owner_items", cfg="cfail3")] fn method(mut self) {} } @@ -273,11 +273,11 @@ trait TraitChangeModeSelfOwnToRef { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeModeSelfOwnToRef { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(&self); } @@ -290,11 +290,11 @@ trait TraitAddUnsafeModifier { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddUnsafeModifier { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] unsafe fn method(); } @@ -307,11 +307,11 @@ trait TraitAddExternModifier { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddExternModifier { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] extern fn method(); } @@ -324,11 +324,11 @@ trait TraitChangeExternCToRustIntrinsic { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeExternCToRustIntrinsic { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] extern "stdcall" fn method(); } @@ -341,11 +341,11 @@ trait TraitAddTypeParameterToMethod { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddTypeParameterToMethod { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(); } @@ -358,11 +358,11 @@ trait TraitAddLifetimeParameterToMethod { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddLifetimeParameterToMethod { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method<'a>(); } @@ -379,11 +379,11 @@ trait TraitAddTraitBoundToMethodTypeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddTraitBoundToMethodTypeParameter { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(); } @@ -396,11 +396,11 @@ trait TraitAddBuiltinBoundToMethodTypeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddBuiltinBoundToMethodTypeParameter { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(); } @@ -413,11 +413,11 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddLifetimeBoundToMethodLifetimeParameter { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method<'a, 'b: 'a>(a: &'a u32, b: &'b u32); } @@ -430,11 +430,11 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondTraitBoundToMethodTypeParameter { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(); } @@ -447,11 +447,11 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(); } @@ -464,11 +464,11 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method<'a, 'b, 'c: 'a + 'b>(a: &'a u32, b: &'b u32, c: &'c u32); } @@ -478,14 +478,14 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[cfg(cfail1)] trait TraitAddAssociatedType { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(); } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddAssociatedType { type Associated; @@ -506,11 +506,11 @@ trait TraitAddTraitBoundToAssociatedType { // Apparently the type bound contributes to the predicates of the trait, but // does not change the associated item itself. #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddTraitBoundToAssociatedType { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] type Associated: ReferencedTrait0; fn method(); @@ -527,11 +527,11 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddLifetimeBoundToAssociatedType<'a> { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] type Associated: 'a; fn method(); @@ -548,11 +548,11 @@ trait TraitAddDefaultToAssociatedType { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddDefaultToAssociatedType { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] type Associated = ReferenceType0; fn method(); @@ -567,8 +567,8 @@ trait TraitAddAssociatedConstant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddAssociatedConstant { const Value: u32; @@ -586,15 +586,15 @@ trait TraitAddInitializerToAssociatedConstant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddInitializerToAssociatedConstant { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] const Value: u32 = 1; - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(); } @@ -609,15 +609,15 @@ trait TraitChangeTypeOfAssociatedConstant { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeTypeOfAssociatedConstant { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] const Value: f64; - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(); } @@ -628,8 +628,8 @@ trait TraitChangeTypeOfAssociatedConstant { trait TraitAddSuperTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSuperTrait : ReferencedTrait0 { } @@ -639,8 +639,8 @@ trait TraitAddSuperTrait : ReferencedTrait0 { } trait TraitAddBuiltiBound { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddBuiltiBound : Send { } @@ -650,8 +650,8 @@ trait TraitAddBuiltiBound : Send { } trait TraitAddStaticLifetimeBound { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddStaticLifetimeBound : 'static { } @@ -661,16 +661,16 @@ trait TraitAddStaticLifetimeBound : 'static { } trait TraitAddTraitAsSecondBound : ReferencedTrait0 { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { } #[cfg(cfail1)] trait TraitAddTraitAsSecondBoundFromBuiltin : Send { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } @@ -680,16 +680,16 @@ trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { } #[cfg(cfail1)] trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } @@ -699,16 +699,16 @@ trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { } #[cfg(cfail1)] trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } @@ -718,8 +718,8 @@ trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } trait TraitAddTypeParameterToTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddTypeParameterToTrait { } @@ -729,8 +729,8 @@ trait TraitAddTypeParameterToTrait { } trait TraitAddLifetimeParameterToTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddLifetimeParameterToTrait<'a> { } @@ -740,8 +740,8 @@ trait TraitAddLifetimeParameterToTrait<'a> { } trait TraitAddTraitBoundToTypeParameterOfTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddTraitBoundToTypeParameterOfTrait { } @@ -751,8 +751,8 @@ trait TraitAddTraitBoundToTypeParameterOfTrait { } trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } @@ -762,8 +762,8 @@ trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a, 'b> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { } @@ -773,8 +773,8 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { } trait TraitAddBuiltinBoundToTypeParameterOfTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddBuiltinBoundToTypeParameterOfTrait { } @@ -784,8 +784,8 @@ trait TraitAddBuiltinBoundToTypeParameterOfTrait { } trait TraitAddSecondTypeParameterToTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondTypeParameterToTrait { } @@ -795,8 +795,8 @@ trait TraitAddSecondTypeParameterToTrait { } trait TraitAddSecondLifetimeParameterToTrait<'a> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { } @@ -806,8 +806,8 @@ trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { } trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } @@ -817,8 +817,8 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } @@ -828,8 +828,8 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b, 'c> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> { } @@ -839,8 +839,8 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait { } @@ -855,8 +855,8 @@ struct ReferenceType1 {} trait TraitAddTraitBoundToTypeParameterOfTraitWhere { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 { } @@ -866,8 +866,8 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } @@ -877,8 +877,8 @@ trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b { } @@ -888,8 +888,8 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } @@ -899,8 +899,8 @@ trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere where T: ReferencedTrait0 + ReferencedTrait1 { } @@ -911,8 +911,8 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { } @@ -922,8 +922,8 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b + 'c { } @@ -933,8 +933,8 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> whe trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere where T: Send + Sync { } @@ -945,11 +945,11 @@ mod change_return_type_of_method_indirectly_use { #[cfg(not(cfail1))] use super::ReferenceType1 as ReturnType; - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeReturnType { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method() -> ReturnType; } } @@ -963,11 +963,11 @@ mod change_method_parameter_type_indirectly_by_use { #[cfg(not(cfail1))] use super::ReferenceType1 as ArgType; - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeArgType { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(a: ArgType); } } @@ -981,11 +981,11 @@ mod change_method_parameter_type_bound_indirectly_by_use { #[cfg(not(cfail1))] use super::ReferencedTrait1 as Bound; - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeBoundOfMethodTypeParameter { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(a: T); } } @@ -1000,11 +1000,11 @@ mod change_method_parameter_type_bound_indirectly_by_use_where { #[cfg(not(cfail1))] use super::ReferencedTrait1 as Bound; - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeBoundOfMethodTypeParameterWhere { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method(a: T) where T: Bound; } } @@ -1018,8 +1018,8 @@ mod change_method_type_parameter_bound_indirectly { #[cfg(not(cfail1))] use super::ReferencedTrait1 as Bound; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeTraitBound { fn method(a: T); } @@ -1035,8 +1035,8 @@ mod change_method_type_parameter_bound_indirectly_where { #[cfg(not(cfail1))] use super::ReferencedTrait1 as Bound; - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] trait TraitChangeTraitBoundWhere where T: Bound { fn method(a: T); } diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs index fa28b2ebedd..70e066870b6 100644 --- a/src/test/incremental/hashes/trait_impls.rs +++ b/src/test/incremental/hashes/trait_impls.rs @@ -30,18 +30,18 @@ impl ChangeMethodNameTrait for Foo { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] pub trait ChangeMethodNameTrait { - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method_name2(); } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl ChangeMethodNameTrait for Foo { - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method_name2() { } } @@ -59,13 +59,13 @@ impl ChangeMethodBodyTrait for Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl ChangeMethodBodyTrait for Foo { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_dirty(label="hir_owner_items", cfg="cfail2")] + #[rustc_clean(label="hir_owner_items", cfg="cfail3")] fn method_name() { () } @@ -86,13 +86,13 @@ impl ChangeMethodBodyTraitInlined for Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl ChangeMethodBodyTraitInlined for Foo { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] - #[rustc_dirty(label="HirBody", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_dirty(label="hir_owner_items", cfg="cfail2")] + #[rustc_clean(label="hir_owner_items", cfg="cfail3")] #[inline] fn method_name() { panic!() @@ -117,11 +117,11 @@ pub trait ChangeMethodSelfnessTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl ChangeMethodSelfnessTrait for Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method_name(&self) { () } @@ -145,11 +145,11 @@ pub trait RemoveMethodSelfnessTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl RemoveMethodSelfnessTrait for Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method_name() {} } @@ -171,11 +171,11 @@ pub trait ChangeMethodSelfmutnessTrait { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl ChangeMethodSelfmutnessTrait for Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method_name(&mut self) {} } @@ -197,8 +197,8 @@ pub trait ChangeItemKindTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl ChangeItemKindTrait for Foo { type name = (); } @@ -223,8 +223,8 @@ pub trait RemoveItemTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl RemoveItemTrait for Foo { type TypeName = (); } @@ -248,8 +248,8 @@ pub trait AddItemTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl AddItemTrait for Foo { type TypeName = (); fn method_name() { } @@ -268,17 +268,17 @@ impl ChangeHasValueTrait for Foo { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] pub trait ChangeHasValueTrait { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method_name() { } } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl ChangeHasValueTrait for Foo { fn method_name() { } } @@ -295,11 +295,11 @@ impl AddDefaultTrait for Foo { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl AddDefaultTrait for Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] default fn method_name() { } } @@ -321,11 +321,11 @@ pub trait AddArgumentTrait { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl AddArgumentTrait for Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method_name(&self, _x: u32) { } } @@ -347,11 +347,11 @@ pub trait ChangeArgumentTypeTrait { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl ChangeArgumentTypeTrait for Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn method_name(&self, _x: char) { } } @@ -370,11 +370,11 @@ impl AddTypeParameterToImpl for Bar { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl AddTypeParameterToImpl for Bar { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn id(t: T) -> T { t } } @@ -391,11 +391,11 @@ impl ChangeSelfTypeOfImpl for u32 { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl ChangeSelfTypeOfImpl for u64 { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn id(self) -> Self { self } } @@ -412,11 +412,11 @@ impl AddLifetimeBoundToImplParameter for T { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl AddLifetimeBoundToImplParameter for T { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn id(self) -> Self { self } } @@ -433,11 +433,11 @@ impl AddTraitBoundToImplParameter for T { } #[cfg(not(cfail1))] -#[rustc_dirty(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_dirty(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl AddTraitBoundToImplParameter for T { - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] fn id(self) -> Self { self } } @@ -454,11 +454,11 @@ impl AddNoMangleToMethod for Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl AddNoMangleToMethod for Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] #[no_mangle] fn add_no_mangle_to_method(&self) { } } @@ -475,11 +475,11 @@ impl MakeMethodInline for Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_clean(label="Hir", cfg="cfail3")] +#[rustc_clean(label="hir_owner", cfg="cfail2")] +#[rustc_clean(label="hir_owner", cfg="cfail3")] impl MakeMethodInline for Foo { - #[rustc_dirty(label="Hir", cfg="cfail2")] - #[rustc_clean(label="Hir", cfg="cfail3")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail3")] #[inline] fn make_method_inline(&self) -> u8 { 0 } } diff --git a/src/test/incremental/hashes/type_defs.rs b/src/test/incremental/hashes/type_defs.rs index 264e8f926ff..bbe1514ba9f 100644 --- a/src/test/incremental/hashes/type_defs.rs +++ b/src/test/incremental/hashes/type_defs.rs @@ -24,7 +24,7 @@ type ChangePrimitiveType = i32; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type ChangePrimitiveType = i64; @@ -35,7 +35,7 @@ type ChangePrimitiveType = i64; type ChangeMutability = &'static i32; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type ChangeMutability = &'static mut i32; @@ -46,7 +46,7 @@ type ChangeMutability = &'static mut i32; type ChangeLifetime<'a> = (&'static i32, &'a i32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type ChangeLifetime<'a> = (&'a i32, &'a i32); @@ -60,7 +60,7 @@ struct Struct2; type ChangeTypeStruct = Struct1; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type ChangeTypeStruct = Struct2; @@ -71,7 +71,7 @@ type ChangeTypeStruct = Struct2; type ChangeTypeTuple = (u32, u64); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type ChangeTypeTuple = (u32, i64); @@ -91,7 +91,7 @@ enum Enum2 { type ChangeTypeEnum = Enum1; #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type ChangeTypeEnum = Enum2; @@ -102,7 +102,7 @@ type ChangeTypeEnum = Enum2; type AddTupleField = (i32, i64); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type AddTupleField = (i32, i64, i16); @@ -113,7 +113,7 @@ type AddTupleField = (i32, i64, i16); type ChangeNestedTupleField = (i32, (i64, i16)); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type ChangeNestedTupleField = (i32, (i64, i8)); @@ -124,7 +124,7 @@ type ChangeNestedTupleField = (i32, (i64, i8)); type AddTypeParam = (T1, T1); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type AddTypeParam = (T1, T2); @@ -135,7 +135,7 @@ type AddTypeParam = (T1, T2); type AddTypeParamBound = (T1, u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type AddTypeParamBound = (T1, u32); @@ -146,7 +146,7 @@ type AddTypeParamBound = (T1, u32); type AddTypeParamBoundWhereClause where T1: Clone = (T1, u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type AddTypeParamBoundWhereClause where T1: Clone+Copy = (T1, u32); @@ -157,7 +157,7 @@ type AddTypeParamBoundWhereClause where T1: Clone+Copy = (T1, u32); type AddLifetimeParam<'a> = (&'a u32, &'a u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32); @@ -168,7 +168,7 @@ type AddLifetimeParam<'a, 'b> = (&'a u32, &'b u32); type AddLifetimeParamBound<'a, 'b> = (&'a u32, &'b u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type AddLifetimeParamBound<'a, 'b: 'a> = (&'a u32, &'b u32); @@ -181,7 +181,7 @@ where 'b: 'a = (&'a u32, &'b u32, &'c u32); #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type AddLifetimeParamBoundWhereClause<'a, 'b, 'c> where 'b: 'a, @@ -200,7 +200,7 @@ mod change_trait_bound_indirectly { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type ChangeTraitBoundIndirectly = (T, u32); } @@ -214,7 +214,7 @@ mod change_trait_bound_indirectly_in_where_clause { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] + #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_items")] #[rustc_clean(cfg="cfail3")] type ChangeTraitBoundIndirectly where T : Trait = (T, u32); } diff --git a/src/test/incremental/hashes/unary_and_binary_exprs.rs b/src/test/incremental/hashes/unary_and_binary_exprs.rs index 776a0273ca7..89aa0b1a58b 100644 --- a/src/test/incremental/hashes/unary_and_binary_exprs.rs +++ b/src/test/incremental/hashes/unary_and_binary_exprs.rs @@ -21,7 +21,7 @@ pub fn const_negation() -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn const_negation() -> i32 { -1 @@ -36,7 +36,7 @@ pub fn const_bitwise_not() -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn const_bitwise_not() -> i32 { !99 @@ -51,7 +51,7 @@ pub fn var_negation(x: i32, y: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn var_negation(x: i32, y: i32) -> i32 { -y @@ -66,7 +66,7 @@ pub fn var_bitwise_not(x: i32, y: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn var_bitwise_not(x: i32, y: i32) -> i32 { !y @@ -81,7 +81,7 @@ pub fn var_deref(x: &i32, y: &i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built,typeck_tables_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn var_deref(x: &i32, y: &i32) -> i32 { *y @@ -96,7 +96,7 @@ pub fn first_const_add() -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn first_const_add() -> i32 { 2 + 3 @@ -111,7 +111,7 @@ pub fn second_const_add() -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn second_const_add() -> i32 { 1 + 3 @@ -126,7 +126,7 @@ pub fn first_var_add(a: i32, b: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn first_var_add(a: i32, b: i32) -> i32 { b + 2 @@ -141,7 +141,7 @@ pub fn second_var_add(a: i32, b: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn second_var_add(a: i32, b: i32) -> i32 { 1 + b @@ -156,7 +156,7 @@ pub fn plus_to_minus(a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn plus_to_minus(a: i32) -> i32 { 1 - a @@ -171,7 +171,7 @@ pub fn plus_to_mult(a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn plus_to_mult(a: i32) -> i32 { 1 * a @@ -186,7 +186,7 @@ pub fn plus_to_div(a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn plus_to_div(a: i32) -> i32 { 1 / a @@ -201,7 +201,7 @@ pub fn plus_to_mod(a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn plus_to_mod(a: i32) -> i32 { 1 % a @@ -216,7 +216,7 @@ pub fn and_to_or(a: bool, b: bool) -> bool { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn and_to_or(a: bool, b: bool) -> bool { a || b @@ -231,7 +231,7 @@ pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 { 1 | a @@ -246,7 +246,7 @@ pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 { 1 ^ a @@ -261,7 +261,7 @@ pub fn bitwise_and_to_lshift(a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn bitwise_and_to_lshift(a: i32) -> i32 { a << 1 @@ -276,7 +276,7 @@ pub fn bitwise_and_to_rshift(a: i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn bitwise_and_to_rshift(a: i32) -> i32 { a >> 1 @@ -291,7 +291,7 @@ pub fn eq_to_uneq(a: i32) -> bool { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn eq_to_uneq(a: i32) -> bool { a != 1 @@ -306,7 +306,7 @@ pub fn eq_to_lt(a: i32) -> bool { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn eq_to_lt(a: i32) -> bool { a < 1 @@ -321,7 +321,7 @@ pub fn eq_to_gt(a: i32) -> bool { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn eq_to_gt(a: i32) -> bool { a > 1 @@ -336,7 +336,7 @@ pub fn eq_to_le(a: i32) -> bool { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn eq_to_le(a: i32) -> bool { a <= 1 @@ -351,7 +351,7 @@ pub fn eq_to_ge(a: i32) -> bool { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn eq_to_ge(a: i32) -> bool { a >= 1 @@ -368,7 +368,7 @@ pub fn type_cast(a: u8) -> u64 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built,typeck_tables_of", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built,typeck_tables_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn type_cast(a: u8) -> u64 { let b = a as u32; @@ -385,7 +385,7 @@ pub fn value_cast(a: u32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn value_cast(a: u32) -> i32 { 2 as i32 @@ -403,7 +403,7 @@ pub fn place() -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn place() -> i32 { let mut x = 10; @@ -423,7 +423,7 @@ pub fn rvalue() -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn rvalue() -> i32 { let mut x = 10; @@ -440,7 +440,7 @@ pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built", cfg="cfail2")] +#[rustc_clean(except="hir_owner_items,optimized_mir,mir_built", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 { s[j] diff --git a/src/test/incremental/hashes/while_let_loops.rs b/src/test/incremental/hashes/while_let_loops.rs index 76e22c6053f..bf49adc9283 100644 --- a/src/test/incremental/hashes/while_let_loops.rs +++ b/src/test/incremental/hashes/while_let_loops.rs @@ -26,7 +26,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; @@ -49,7 +49,7 @@ pub fn change_loop_condition() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_condition() { let mut _x = 0; @@ -71,7 +71,7 @@ pub fn add_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_break() { let mut _x = 0; @@ -94,7 +94,7 @@ pub fn add_loop_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label() { let mut _x = 0; @@ -117,7 +117,7 @@ pub fn add_loop_label_to_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label_to_break() { let mut _x = 0; @@ -142,7 +142,7 @@ pub fn change_break_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_break_label() { let mut _x = 0; @@ -167,7 +167,7 @@ pub fn add_loop_label_to_continue() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label_to_continue() { let mut _x = 0; @@ -192,7 +192,7 @@ pub fn change_continue_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_continue_label() { let mut _x = 0; @@ -217,7 +217,7 @@ pub fn change_continue_to_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/src/test/incremental/hashes/while_loops.rs b/src/test/incremental/hashes/while_loops.rs index 3253f4570b1..4839bf9a6eb 100644 --- a/src/test/incremental/hashes/while_loops.rs +++ b/src/test/incremental/hashes/while_loops.rs @@ -26,7 +26,7 @@ pub fn change_loop_body() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_body() { let mut _x = 0; @@ -49,7 +49,7 @@ pub fn change_loop_condition() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_loop_condition() { let mut _x = 0; @@ -71,7 +71,7 @@ pub fn add_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_break() { let mut _x = 0; @@ -94,7 +94,7 @@ pub fn add_loop_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label() { let mut _x = 0; @@ -117,7 +117,7 @@ pub fn add_loop_label_to_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label_to_break() { let mut _x = 0; @@ -142,7 +142,7 @@ pub fn change_break_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_break_label() { let mut _x = 0; @@ -167,7 +167,7 @@ pub fn add_loop_label_to_continue() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items")] #[rustc_clean(cfg="cfail3")] pub fn add_loop_label_to_continue() { let mut _x = 0; @@ -192,7 +192,7 @@ pub fn change_continue_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built")] #[rustc_clean(cfg="cfail3")] pub fn change_continue_label() { let mut _x = 0; @@ -217,7 +217,7 @@ pub fn change_continue_to_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="hir_owner_items, mir_built, optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/src/test/incremental/ich_method_call_trait_scope.rs b/src/test/incremental/ich_method_call_trait_scope.rs index 9dfd2ae2511..a9ec66346ac 100644 --- a/src/test/incremental/ich_method_call_trait_scope.rs +++ b/src/test/incremental/ich_method_call_trait_scope.rs @@ -26,15 +26,15 @@ mod mod3 { #[cfg(rpass2)] use Trait2; - #[rustc_clean(label="Hir", cfg="rpass2")] - #[rustc_clean(label="HirBody", cfg="rpass2")] + #[rustc_clean(label="hir_owner", cfg="rpass2")] + #[rustc_clean(label="hir_owner_items", cfg="rpass2")] #[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] fn bar() { ().method(); } - #[rustc_clean(label="Hir", cfg="rpass2")] - #[rustc_clean(label="HirBody", cfg="rpass2")] + #[rustc_clean(label="hir_owner", cfg="rpass2")] + #[rustc_clean(label="hir_owner_items", cfg="rpass2")] #[rustc_clean(label="typeck_tables_of", cfg="rpass2")] fn baz() { 22; // no method call, traits in scope don't matter diff --git a/src/test/incremental/ich_nested_items.rs b/src/test/incremental/ich_nested_items.rs index b2b7e663151..a9232190eef 100644 --- a/src/test/incremental/ich_nested_items.rs +++ b/src/test/incremental/ich_nested_items.rs @@ -7,18 +7,21 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] -#[rustc_clean(label="Hir", cfg="cfail2")] -#[rustc_dirty(label="HirBody", cfg="cfail2")] +#[rustc_clean(label = "hir_owner", cfg = "cfail2")] +#[rustc_dirty(label = "hir_owner_items", cfg = "cfail2")] pub fn foo() { #[cfg(cfail1)] - pub fn baz() { } // order is different... + pub fn baz() {} // order is different... - #[rustc_clean(label="Hir", cfg="cfail2")] - #[rustc_clean(label="HirBody", cfg="cfail2")] - pub fn bar() { } // but that doesn't matter. + // FIXME: Make "hir_owner" use `rustc_clean` here. Currently "hir_owner" includes a reference to + // the parent node, which is the statement holding this item. Changing the position of + // `bar` in `foo` will update that reference and make `hir_owner(bar)` dirty. + #[rustc_dirty(label = "hir_owner", cfg = "cfail2")] + #[rustc_clean(label = "hir_owner_items", cfg = "cfail2")] + pub fn bar() {} // but that doesn't matter. #[cfg(cfail2)] - pub fn baz() { } // order is different... + pub fn baz() {} // order is different... - pub fn bap() { } // neither does adding a new item + pub fn bap() {} // neither does adding a new item } diff --git a/src/test/incremental/ich_resolve_results.rs b/src/test/incremental/ich_resolve_results.rs index 0e4ab6b78e2..c4674faabf5 100644 --- a/src/test/incremental/ich_resolve_results.rs +++ b/src/test/incremental/ich_resolve_results.rs @@ -28,18 +28,18 @@ mod mod3 { #[cfg(rpass3)] use mod2::Foo; - #[rustc_clean(label="Hir", cfg="rpass2")] - #[rustc_clean(label="HirBody", cfg="rpass2")] - #[rustc_clean(label="Hir", cfg="rpass3")] - #[rustc_dirty(label="HirBody", cfg="rpass3")] + #[rustc_clean(label="hir_owner", cfg="rpass2")] + #[rustc_clean(label="hir_owner_items", cfg="rpass2")] + #[rustc_clean(label="hir_owner", cfg="rpass3")] + #[rustc_dirty(label="hir_owner_items", cfg="rpass3")] fn in_expr() { Foo(0); } - #[rustc_clean(label="Hir", cfg="rpass2")] - #[rustc_clean(label="HirBody", cfg="rpass2")] - #[rustc_clean(label="Hir", cfg="rpass3")] - #[rustc_dirty(label="HirBody", cfg="rpass3")] + #[rustc_clean(label="hir_owner", cfg="rpass2")] + #[rustc_clean(label="hir_owner_items", cfg="rpass2")] + #[rustc_clean(label="hir_owner", cfg="rpass3")] + #[rustc_dirty(label="hir_owner_items", cfg="rpass3")] fn in_type() { test::(); } diff --git a/src/test/incremental/inlined_hir_34991/main.rs b/src/test/incremental/inlined_hir_34991/main.rs index 819b8434b08..bb76a0bb8fe 100644 --- a/src/test/incremental/inlined_hir_34991/main.rs +++ b/src/test/incremental/inlined_hir_34991/main.rs @@ -1,6 +1,6 @@ // Regression test for #34991: an ICE occurred here because we inline // some of the vector routines and give them a local def-id `X`. This -// got hashed after codegen (`Hir(X)`). When we load back up, we get an +// got hashed after codegen (`hir_owner(X)`). When we load back up, we get an // error because the `X` is remapped to the original def-id (in // libstd), and we can't hash a HIR node from std. diff --git a/src/test/incremental/issue-69596.rs b/src/test/incremental/issue-69596.rs new file mode 100644 index 00000000000..dc587fdc44b --- /dev/null +++ b/src/test/incremental/issue-69596.rs @@ -0,0 +1,21 @@ +// revisions: rpass1 rpass2 + +#![allow(unused_imports)] + +#[macro_export] +macro_rules! a_macro { + () => {}; +} + +#[cfg(rpass1)] +use a_macro as same_name; + +mod same_name {} + +mod needed_mod { + fn _crash() { + use super::same_name; + } +} + +fn main() {} diff --git a/src/test/incremental/source_loc_macros.rs b/src/test/incremental/source_loc_macros.rs index 51ea7d6d447..a360a66a64b 100644 --- a/src/test/incremental/source_loc_macros.rs +++ b/src/test/incremental/source_loc_macros.rs @@ -7,26 +7,26 @@ #![feature(rustc_attrs)] -#[rustc_clean(label="Hir", cfg="rpass2")] -#[rustc_clean(label="HirBody", cfg="rpass2")] +#[rustc_clean(label="hir_owner", cfg="rpass2")] +#[rustc_clean(label="hir_owner_items", cfg="rpass2")] fn line_same() { let _ = line!(); } -#[rustc_clean(label="Hir", cfg="rpass2")] -#[rustc_clean(label="HirBody", cfg="rpass2")] +#[rustc_clean(label="hir_owner", cfg="rpass2")] +#[rustc_clean(label="hir_owner_items", cfg="rpass2")] fn col_same() { let _ = column!(); } -#[rustc_clean(label="Hir", cfg="rpass2")] -#[rustc_clean(label="HirBody", cfg="rpass2")] +#[rustc_clean(label="hir_owner", cfg="rpass2")] +#[rustc_clean(label="hir_owner_items", cfg="rpass2")] fn file_same() { let _ = file!(); } -#[rustc_clean(label="Hir", cfg="rpass2")] -#[rustc_dirty(label="HirBody", cfg="rpass2")] +#[rustc_clean(label="hir_owner", cfg="rpass2")] +#[rustc_dirty(label="hir_owner_items", cfg="rpass2")] fn line_different() { #[cfg(rpass1)] { @@ -38,8 +38,8 @@ fn line_different() { } } -#[rustc_clean(label="Hir", cfg="rpass2")] -#[rustc_dirty(label="HirBody", cfg="rpass2")] +#[rustc_clean(label="hir_owner", cfg="rpass2")] +#[rustc_dirty(label="hir_owner_items", cfg="rpass2")] fn col_different() { #[cfg(rpass1)] { diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub1.rs b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs index 54fbe4465e3..2927ddec4e5 100644 --- a/src/test/incremental/span_hash_stable/auxiliary/sub1.rs +++ b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs @@ -1,4 +1,4 @@ -#[rustc_clean(label="Hir", cfg="rpass2")] +#[rustc_clean(label="hir_owner", cfg="rpass2")] pub struct SomeType { pub x: u32, pub y: i64, diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub2.rs b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs index 34957616856..aa635077db8 100644 --- a/src/test/incremental/span_hash_stable/auxiliary/sub2.rs +++ b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs @@ -1,4 +1,4 @@ -#[rustc_clean(label="Hir", cfg="rpass2")] +#[rustc_clean(label="hir_owner", cfg="rpass2")] pub struct SomeOtherType { pub a: i32, pub b: u64, diff --git a/src/test/incremental/spans_significant_w_debuginfo.rs b/src/test/incremental/spans_significant_w_debuginfo.rs index e6fdc7cb3a0..b87d829132b 100644 --- a/src/test/incremental/spans_significant_w_debuginfo.rs +++ b/src/test/incremental/spans_significant_w_debuginfo.rs @@ -12,6 +12,6 @@ pub fn main() {} #[cfg(rpass2)] -#[rustc_dirty(label="Hir", cfg="rpass2")] -#[rustc_dirty(label="HirBody", cfg="rpass2")] +#[rustc_dirty(label="hir_owner", cfg="rpass2")] +#[rustc_dirty(label="hir_owner_items", cfg="rpass2")] pub fn main() {} diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs index 834a1d90e3f..7b51e1381ae 100644 --- a/src/test/incremental/string_constant.rs +++ b/src/test/incremental/string_constant.rs @@ -19,7 +19,7 @@ pub mod x { } #[cfg(cfail2)] - #[rustc_dirty(label="HirBody", cfg="cfail2")] + #[rustc_dirty(label="hir_owner_items", cfg="cfail2")] #[rustc_dirty(label="optimized_mir", cfg="cfail2")] pub fn x() { println!("{}", "2"); diff --git a/src/test/incremental/thinlto/cgu_invalidated_when_import_added.rs b/src/test/incremental/thinlto/cgu_invalidated_when_import_added.rs index 42168dd273e..9c17c8745f8 100644 --- a/src/test/incremental/thinlto/cgu_invalidated_when_import_added.rs +++ b/src/test/incremental/thinlto/cgu_invalidated_when_import_added.rs @@ -4,7 +4,7 @@ // rust-lang/rust#59535: // -// This is analgous to cgu_invalidated_when_import_removed.rs, but it covers +// This is analogous to cgu_invalidated_when_import_removed.rs, but it covers // the other direction: // // We start with a call-graph like `[A] -> [B -> D] [C]` (where the letters are diff --git a/src/test/incremental/thinlto/cgu_invalidated_when_import_removed.rs b/src/test/incremental/thinlto/cgu_invalidated_when_import_removed.rs index 19ce7b3e148..1214e37f982 100644 --- a/src/test/incremental/thinlto/cgu_invalidated_when_import_removed.rs +++ b/src/test/incremental/thinlto/cgu_invalidated_when_import_removed.rs @@ -41,7 +41,7 @@ mod foo { // In cfail2, ThinLTO decides that foo() does not get inlined into main, and // instead bar() gets inlined into foo(). But faulty logic in our incr. // ThinLTO implementation thought that `main()` is unchanged and thus reused - // the object file still containing a call to the now non-existant bar(). + // the object file still containing a call to the now non-existent bar(). pub fn foo(){ bar() } diff --git a/src/test/incremental/unchecked_dirty_clean.rs b/src/test/incremental/unchecked_dirty_clean.rs index 66bdb670167..3bc8818aa6f 100644 --- a/src/test/incremental/unchecked_dirty_clean.rs +++ b/src/test/incremental/unchecked_dirty_clean.rs @@ -10,13 +10,13 @@ fn main() { - #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute { // empty block } - #[rustc_clean(label="Hir", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute { // empty block @@ -24,11 +24,11 @@ fn main() { } struct _Struct { - #[rustc_dirty(label="Hir", cfg="cfail2")] + #[rustc_dirty(label="hir_owner", cfg="cfail2")] //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute _field1: i32, - #[rustc_clean(label="Hir", cfg="cfail2")] + #[rustc_clean(label="hir_owner", cfg="cfail2")] //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute _field2: i32, } diff --git a/src/test/incremental/warnings-reemitted.rs b/src/test/incremental/warnings-reemitted.rs index 5fc89395827..0eac2a1d57f 100644 --- a/src/test/incremental/warnings-reemitted.rs +++ b/src/test/incremental/warnings-reemitted.rs @@ -2,8 +2,8 @@ // compile-flags: -Coverflow-checks=on // build-pass (FIXME(62277): could be check-pass?) -#![warn(const_err)] +#![warn(arithmetic_overflow)] fn main() { - let _ = 255u8 + 1; //~ WARNING attempt to add with overflow + let _ = 255u8 + 1; //~ WARNING operation will overflow } diff --git a/src/test/mir-opt/const-promotion-extern-static.rs b/src/test/mir-opt/const-promotion-extern-static.rs index f6f7d091091..c858a4c5ee7 100644 --- a/src/test/mir-opt/const-promotion-extern-static.rs +++ b/src/test/mir-opt/const-promotion-extern-static.rs @@ -4,9 +4,9 @@ extern "C" { static Y: i32 = 42; -static mut BAR: *const &'static i32 = [&Y].as_ptr(); +static mut BAR: *const &i32 = [&Y].as_ptr(); -static mut FOO: *const &'static i32 = [unsafe { &X }].as_ptr(); +static mut FOO: *const &i32 = [unsafe { &X }].as_ptr(); fn main() {} @@ -14,12 +14,12 @@ fn main() {} // START rustc.FOO.PromoteTemps.before.mir // bb0: { // ... -// _5 = const Scalar(alloc1+0) : &i32; +// _5 = const {alloc1+0: &i32}; // _4 = &(*_5); // _3 = [move _4]; // _2 = &_3; -// _1 = move _2 as &[&'static i32] (Pointer(Unsize)); -// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; +// _1 = move _2 as &[&i32] (Pointer(Unsize)); +// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // } // ... // bb2: { @@ -31,12 +31,12 @@ fn main() {} // START rustc.BAR.PromoteTemps.before.mir // bb0: { // ... -// _5 = const Scalar(alloc0+0) : &i32; +// _5 = const {alloc0+0: &i32}; // _4 = &(*_5); // _3 = [move _4]; // _2 = &_3; -// _1 = move _2 as &[&'static i32] (Pointer(Unsize)); -// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; +// _1 = move _2 as &[&i32] (Pointer(Unsize)); +// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // } // ... // bb2: { @@ -50,8 +50,8 @@ fn main() {} // ... // _6 = const BAR::promoted[0]; // _2 = &(*_6); -// _1 = move _2 as &[&'static i32] (Pointer(Unsize)); -// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; +// _1 = move _2 as &[&i32] (Pointer(Unsize)); +// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // } // ... // bb2: { @@ -63,8 +63,8 @@ fn main() {} // ... // _6 = const FOO::promoted[0]; // _2 = &(*_6); -// _1 = move _2 as &[&'static i32] (Pointer(Unsize)); -// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; +// _1 = move _2 as &[&i32] (Pointer(Unsize)); +// _0 = const core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // } // ... // bb2: { diff --git a/src/test/mir-opt/const_prop/discriminant.rs b/src/test/mir-opt/const_prop/discriminant.rs index 667d21fc14e..636aa1af653 100644 --- a/src/test/mir-opt/const_prop/discriminant.rs +++ b/src/test/mir-opt/const_prop/discriminant.rs @@ -31,7 +31,7 @@ fn main() { // START rustc.main.ConstProp.after.mir // bb0: { // ... -// _3 = const Scalar(0x01) : std::option::Option; +// _3 = const {transmute(0x01): std::option::Option}; // _4 = const 1isize; // switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // } diff --git a/src/test/mir-opt/const_prop/issue-66971.rs b/src/test/mir-opt/const_prop/issue-66971.rs index 30c75303b3e..f332bb89509 100644 --- a/src/test/mir-opt/const_prop/issue-66971.rs +++ b/src/test/mir-opt/const_prop/issue-66971.rs @@ -29,7 +29,7 @@ fn main() { // START rustc.main.ConstProp.after.mir // bb0: { // ... -// _3 = const Scalar() : (); +// _3 = const (); // _2 = (move _3, const 0u8, const 0u8); // ... // _1 = const encode(move _2) -> bb1; diff --git a/src/test/mir-opt/const_prop/read_immutable_static.rs b/src/test/mir-opt/const_prop/read_immutable_static.rs index 693ef783985..d307cebd715 100644 --- a/src/test/mir-opt/const_prop/read_immutable_static.rs +++ b/src/test/mir-opt/const_prop/read_immutable_static.rs @@ -10,10 +10,10 @@ fn main() { // START rustc.main.ConstProp.before.mir // bb0: { // ... -// _3 = const Scalar(alloc0+0) : &u8; +// _3 = const {alloc0+0: &u8}; // _2 = (*_3); // ... -// _5 = const Scalar(alloc0+0) : &u8; +// _5 = const {alloc0+0: &u8}; // _4 = (*_5); // _1 = Add(move _2, move _4); // ... diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs index 4442fa5f521..82b216a99cf 100644 --- a/src/test/mir-opt/generator-storage-dead-unwind.rs +++ b/src/test/mir-opt/generator-storage-dead-unwind.rs @@ -49,7 +49,7 @@ fn main() { // StorageLive(_4); // _4 = Bar(const 6i32,); // ... -// _1 = suspend(move _6) -> [resume: bb2, drop: bb4]; +// _5 = yield(move _6) -> [resume: bb2, drop: bb4]; // } // bb1 (cleanup): { // resume; diff --git a/src/test/mir-opt/generator-tiny.rs b/src/test/mir-opt/generator-tiny.rs new file mode 100644 index 00000000000..09e943bd962 --- /dev/null +++ b/src/test/mir-opt/generator-tiny.rs @@ -0,0 +1,34 @@ +//! Tests that generators that cannot return or unwind don't have unnecessary +//! panic branches. + +// compile-flags: -Zno-landing-pads + +#![feature(generators, generator_trait)] + +struct HasDrop; + +impl Drop for HasDrop { + fn drop(&mut self) {} +} + +fn callee() {} + +fn main() { + let _gen = |_x: u8| { + let _d = HasDrop; + loop { + yield; + callee(); + } + }; +} + +// END RUST SOURCE + +// START rustc.main-{{closure}}.generator_resume.0.mir +// bb0: { +// ... +// switchInt(move _11) -> [0u32: bb1, 3u32: bb5, otherwise: bb6]; +// } +// ... +// END rustc.main-{{closure}}.generator_resume.0.mir diff --git a/src/test/mir-opt/no-drop-for-inactive-variant.rs b/src/test/mir-opt/no-drop-for-inactive-variant.rs new file mode 100644 index 00000000000..74a606af28f --- /dev/null +++ b/src/test/mir-opt/no-drop-for-inactive-variant.rs @@ -0,0 +1,43 @@ +// ignore-wasm32-bare compiled with panic=abort by default + +// Ensure that there are no drop terminators in `unwrap` (except the one along the cleanup +// path). + +fn unwrap(opt: Option) -> T { + match opt { + Some(x) => x, + None => panic!(), + } +} + +fn main() { + let _ = unwrap(Some(1i32)); +} + +// END RUST SOURCE +// START rustc.unwrap.SimplifyCfg-elaborate-drops.after.mir +// fn unwrap(_1: std::option::Option) -> T { +// ... +// bb0: { +// ... +// switchInt(move _2) -> [0isize: bb2, 1isize: bb4, otherwise: bb3]; +// } +// bb1 (cleanup): { +// resume; +// } +// bb2: { +// ... +// const std::rt::begin_panic::<&str>(const "explicit panic") -> bb5; +// } +// bb3: { +// unreachable; +// } +// bb4: { +// ... +// return; +// } +// bb5 (cleanup): { +// drop(_1) -> bb1; +// } +// } +// END rustc.unwrap.SimplifyCfg-elaborate-drops.after.mir diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs index 294fe247c38..ea106eaf595 100644 --- a/src/test/mir-opt/remove_fake_borrows.rs +++ b/src/test/mir-opt/remove_fake_borrows.rs @@ -26,16 +26,16 @@ fn main() { // goto -> bb7; // } // bb2: { -// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb3, otherwise: bb1]; +// switchInt((*(*((_1 as Some).0: &&i32)))) -> [0i32: bb3, otherwise: bb1]; // } // bb3: { // goto -> bb4; // } // bb4: { // _4 = &shallow _1; -// _5 = &shallow ((_1 as Some).0: &' &' i32); -// _6 = &shallow (*((_1 as Some).0: &' &' i32)); -// _7 = &shallow (*(*((_1 as Some).0: &' &' i32))); +// _5 = &shallow ((_1 as Some).0: &&i32); +// _6 = &shallow (*((_1 as Some).0: &&i32)); +// _7 = &shallow (*(*((_1 as Some).0: &&i32))); // StorageLive(_8); // _8 = _2; // switchInt(move _8) -> [false: bb6, otherwise: bb5]; @@ -72,7 +72,7 @@ fn main() { // goto -> bb7; // } // bb2: { -// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb3, otherwise: bb1]; +// switchInt((*(*((_1 as Some).0: &&i32)))) -> [0i32: bb3, otherwise: bb1]; // } // bb3: { // goto -> bb4; diff --git a/src/test/mir-opt/simplify-locals-removes-unused-consts.rs b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs index 6f03438ff72..e427fd55ad6 100644 --- a/src/test/mir-opt/simplify-locals-removes-unused-consts.rs +++ b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs @@ -1,18 +1,18 @@ // compile-flags: -C overflow-checks=no -fn use_zst(_: ((), ())) { } +fn use_zst(_: ((), ())) {} struct Temp { - x: u8 + x: u8, } -fn use_u8(_: u8) { } +fn use_u8(_: u8) {} fn main() { let ((), ()) = ((), ()); use_zst(((), ())); - use_u8((Temp { x : 40 }).x + 2); + use_u8((Temp { x: 40 }).x + 2); } // END RUST SOURCE @@ -35,28 +35,28 @@ fn main() { // bb0: { // StorageLive(_1); // StorageLive(_2); -// _2 = const Scalar() : (); +// _2 = const (); // StorageLive(_3); -// _3 = const Scalar() : (); -// _1 = const Scalar() : ((), ()); +// _3 = const (); +// _1 = const {transmute(()): ((), ())}; // StorageDead(_3); // StorageDead(_2); // StorageDead(_1); // StorageLive(_4); // StorageLive(_6); -// _6 = const Scalar() : (); +// _6 = const (); // StorageLive(_7); -// _7 = const Scalar() : (); +// _7 = const (); // StorageDead(_7); // StorageDead(_6); -// _4 = const use_zst(const Scalar() : ((), ())) -> bb1; +// _4 = const use_zst(const {transmute(()): ((), ())}) -> bb1; // } // bb1: { // StorageDead(_4); // StorageLive(_8); // StorageLive(_10); // StorageLive(_11); -// _11 = const Scalar(0x28) : Temp; +// _11 = const {transmute(0x28) : Temp}; // _10 = const 40u8; // StorageDead(_10); // _8 = const use_u8(const 42u8) -> bb2; @@ -75,7 +75,7 @@ fn main() { // } // bb0: { // StorageLive(_1); -// _1 = const use_zst(const Scalar() : ((), ())) -> bb1; +// _1 = const use_zst(const {transmute(()): ((), ())}) -> bb1; // } // bb1: { // StorageDead(_1); diff --git a/src/test/mir-opt/storage_live_dead_in_statics.rs b/src/test/mir-opt/storage_live_dead_in_statics.rs index 5dc15286bab..1c98766b968 100644 --- a/src/test/mir-opt/storage_live_dead_in_statics.rs +++ b/src/test/mir-opt/storage_live_dead_in_statics.rs @@ -35,12 +35,12 @@ fn main() { // END RUST SOURCE // START rustc.XXX.mir_map.0.mir -// let mut _0: &'static Foo; -// let _1: &'static Foo; +// let mut _0: &Foo; +// let _1: &Foo; // let _2: Foo; -// let mut _3: &'static [(u32, u32)]; -// let mut _4: &'static [(u32, u32); 42]; -// let _5: &'static [(u32, u32); 42]; +// let mut _3: &[(u32, u32)]; +// let mut _4: &[(u32, u32); 42]; +// let _5: &[(u32, u32); 42]; // let _6: [(u32, u32); 42]; // let mut _7: (u32, u32); // let mut _8: (u32, u32); @@ -178,7 +178,7 @@ fn main() { // _6 = [move _7, move _8, move _9, move _10, move _11, move _12, move _13, move _14, move _15, move _16, move _17, move _18, move _19, move _20, move _21, move _22, move _23, move _24, move _25, move _26, move _27, move _28, move _29, move _30, move _31, move _32, move _33, move _34, move _35, move _36, move _37, move _38, move _39, move _40, move _41, move _42, move _43, move _44, move _45, move _46, move _47, move _48]; // _5 = &_6; // _4 = &(*_5); -// _3 = move _4 as &'static [(u32, u32)] (Pointer(Unsize)); +// _3 = move _4 as &[(u32, u32)] (Pointer(Unsize)); // _2 = Foo { tup: const "hi", data: move _3 }; // _1 = &_2; // _0 = &(*_1); diff --git a/src/test/pretty/attr-literals.rs b/src/test/pretty/attr-literals.rs index 9db7e27b161..44d2c5db3e6 100644 --- a/src/test/pretty/attr-literals.rs +++ b/src/test/pretty/attr-literals.rs @@ -5,7 +5,7 @@ #![feature(rustc_attrs)] fn main() { - #![rustc_dummy("hi", 1, 2, 1.012, pi = 3.14, bye, name ("John"))] + #![rustc_dummy("hi", 1, 2, 1.012, pi = 3.14, bye, name("John"))] #[rustc_dummy = 8] fn f() { } diff --git a/src/test/pretty/delimited-token-groups.rs b/src/test/pretty/delimited-token-groups.rs index 7bbb7dc911f..66de0fc6cf7 100644 --- a/src/test/pretty/delimited-token-groups.rs +++ b/src/test/pretty/delimited-token-groups.rs @@ -7,7 +7,7 @@ macro_rules! mac { ($ ($ tt : tt) *) => () } mac! { struct S { field1 : u8, field2 : u16, } impl Clone for S { - fn clone () -> S + fn clone() -> S { panic ! () ; @@ -16,9 +16,8 @@ mac! { } mac! { - a - (aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa - aaaaaaaa aaaaaaaa) a + a(aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa + aaaaaaaa aaaaaaaa) a [aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa] a { diff --git a/src/test/pretty/gat-bounds.pp b/src/test/pretty/gat-bounds.pp deleted file mode 100644 index 0c95add4901..00000000000 --- a/src/test/pretty/gat-bounds.pp +++ /dev/null @@ -1,25 +0,0 @@ -// Check that associated types print generic parameters and where clauses. -// See issue #67509. - -// pretty-compare-only -// pp-exact:gat-bounds.pp - -#![feature(generic_associated_types)] - -trait X { - type - Y: Trait - where - Self: Sized; -} - -impl X for () { - type - Y - where - Self: Sized - = - u32; -} - -fn main() { } diff --git a/src/test/pretty/gat-bounds.rs b/src/test/pretty/gat-bounds.rs index 1275f432a3c..789e4bc80ac 100644 --- a/src/test/pretty/gat-bounds.rs +++ b/src/test/pretty/gat-bounds.rs @@ -2,7 +2,6 @@ // See issue #67509. // pretty-compare-only -// pp-exact:gat-bounds.pp #![feature(generic_associated_types)] diff --git a/src/test/pretty/if-attr.rs b/src/test/pretty/if-attr.rs new file mode 100644 index 00000000000..652604fc7f3 --- /dev/null +++ b/src/test/pretty/if-attr.rs @@ -0,0 +1,37 @@ +// pp-exact + +#[cfg(FALSE)] +fn simple_attr() { + + #[attr] + if true { } + + #[allow_warnings] + if true { } +} + +#[cfg(FALSE)] +fn if_else_chain() { + + #[first_attr] + if true { } else if false { } else { } +} + +#[cfg(FALSE)] +fn if_let() { + + #[attr] + if let Some(_) = Some(true) { } +} + +#[cfg(FALSE)] +fn let_attr_if() { + let _ = #[attr] if let _ = 0 { }; + let _ = #[attr] if true { }; + + let _ = #[attr] if let _ = 0 { } else { }; + let _ = #[attr] if true { } else { }; +} + + +fn main() { } diff --git a/src/test/pretty/issue-12590-a.rs b/src/test/pretty/issue-12590-a.rs index 1a9e85c42d8..ca1fef83cff 100644 --- a/src/test/pretty/issue-12590-a.rs +++ b/src/test/pretty/issue-12590-a.rs @@ -1,4 +1,5 @@ // pp-exact +// pretty-compare-only // The next line should not be expanded diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 8aa4cdeb539..ee7586bae82 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -34,29 +34,29 @@ ((::alloc::fmt::format as for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((::core::fmt::Arguments::new_v1 as - fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments::<'_>::new_v1})((&([("test" - as - &'static str)] - as - [&str; 1]) - as - &[&str; 1]), - (&(match (() - as - ()) - { - () - => - ([] - as - [std::fmt::ArgumentV1<'_>; 0]), - } - as - [std::fmt::ArgumentV1<'_>; 0]) - as - &[std::fmt::ArgumentV1<'_>; 0])) + fn(&[&str], &[std::fmt::ArgumentV1]) -> std::fmt::Arguments {std::fmt::Arguments::new_v1})((&([("test" + as + &str)] + as + [&str; 1]) + as + &[&str; 1]), + (&(match (() + as + ()) + { + () + => + ([] + as + [std::fmt::ArgumentV1; 0]), + } + as + [std::fmt::ArgumentV1; 0]) + as + &[std::fmt::ArgumentV1; 0])) as - std::fmt::Arguments<'_>)) + std::fmt::Arguments)) as std::string::String); (res as std::string::String) } as std::string::String); diff --git a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs index 643ca761aac..031a4825959 100644 --- a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs +++ b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs @@ -12,5 +12,5 @@ const C: C = #[cfg(debug_assertions)] field: 0, - #[cfg(not (debug_assertions))] + #[cfg(not(debug_assertions))] field: 1,}; diff --git a/src/test/pretty/nested-item-vis-defaultness.rs b/src/test/pretty/nested-item-vis-defaultness.rs new file mode 100644 index 00000000000..0a3f2a10c85 --- /dev/null +++ b/src/test/pretty/nested-item-vis-defaultness.rs @@ -0,0 +1,47 @@ +// Check that nested items have their visibility and `default`nesses in the right order. + +// pp-exact + +fn main() { } + +#[cfg(FALSE)] +extern "C" { + static X: u8 ; + type X; + fn foo(); + pub static X: u8 ; + pub type X; + pub fn foo(); +} + +#[cfg(FALSE)] +trait T { + const X: u8 ; + type X; + fn foo(); + default const X: u8 ; + default type X; + default fn foo(); + pub const X: u8 ; + pub type X; + pub fn foo(); + pub default const X: u8 ; + pub default type X; + pub default fn foo(); +} + +#[cfg(FALSE)] +impl T for S { + const X: u8 ; + type X; + fn foo(); + default const X: u8 ; + default type X; + default fn foo(); + pub const X: u8 ; + pub type X; + pub fn foo(); + pub default const X: u8 ; + pub default type X; + pub default fn foo(); +} diff --git a/src/test/pretty/trait-inner-attr.rs b/src/test/pretty/trait-inner-attr.rs new file mode 100644 index 00000000000..bb4fb1459bd --- /dev/null +++ b/src/test/pretty/trait-inner-attr.rs @@ -0,0 +1,7 @@ +// pp-exact + +trait Foo { + #![allow(bar)] +} + +fn main() { } diff --git a/src/test/run-fail/mir_indexing_oob_1.rs b/src/test/run-fail/mir_indexing_oob_1.rs index 0ae0320b124..1cd53e309eb 100644 --- a/src/test/run-fail/mir_indexing_oob_1.rs +++ b/src/test/run-fail/mir_indexing_oob_1.rs @@ -2,7 +2,7 @@ const C: [u32; 5] = [0; 5]; -#[allow(const_err)] +#[allow(unconditional_panic)] fn test() -> u32 { C[10] } diff --git a/src/test/run-fail/mir_indexing_oob_2.rs b/src/test/run-fail/mir_indexing_oob_2.rs index a7a1177260c..64b260993c9 100644 --- a/src/test/run-fail/mir_indexing_oob_2.rs +++ b/src/test/run-fail/mir_indexing_oob_2.rs @@ -2,7 +2,7 @@ const C: &'static [u8; 5] = b"hello"; -#[allow(const_err)] +#[allow(unconditional_panic)] fn test() -> u8 { C[10] } diff --git a/src/test/run-fail/mir_indexing_oob_3.rs b/src/test/run-fail/mir_indexing_oob_3.rs index 188460fff78..3688088439b 100644 --- a/src/test/run-fail/mir_indexing_oob_3.rs +++ b/src/test/run-fail/mir_indexing_oob_3.rs @@ -2,7 +2,7 @@ const C: &'static [u8; 5] = b"hello"; -#[allow(const_err)] +#[allow(unconditional_panic)] fn mir() -> u8 { C[10] } diff --git a/src/test/run-fail/overflowing-add.rs b/src/test/run-fail/overflowing-add.rs index 24602aced9e..5ca91314d95 100644 --- a/src/test/run-fail/overflowing-add.rs +++ b/src/test/run-fail/overflowing-add.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to add with overflow' // compile-flags: -C debug-assertions -#![allow(const_err)] +#![allow(arithmetic_overflow)] fn main() { let _x = 200u8 + 200u8 + 200u8; diff --git a/src/test/run-fail/overflowing-lsh-1.rs b/src/test/run-fail/overflowing-lsh-1.rs index 37fbf01e487..977cfea0fe0 100644 --- a/src/test/run-fail/overflowing-lsh-1.rs +++ b/src/test/run-fail/overflowing-lsh-1.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions -#![warn(exceeding_bitshifts)] +#![warn(arithmetic_overflow)] #![warn(const_err)] fn main() { diff --git a/src/test/run-fail/overflowing-lsh-2.rs b/src/test/run-fail/overflowing-lsh-2.rs index 7b0b37dfed0..3517dacde3a 100644 --- a/src/test/run-fail/overflowing-lsh-2.rs +++ b/src/test/run-fail/overflowing-lsh-2.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions -#![warn(exceeding_bitshifts)] +#![warn(arithmetic_overflow)] #![warn(const_err)] fn main() { diff --git a/src/test/run-fail/overflowing-lsh-3.rs b/src/test/run-fail/overflowing-lsh-3.rs index 1768a8e6d31..4a575c3fa7f 100644 --- a/src/test/run-fail/overflowing-lsh-3.rs +++ b/src/test/run-fail/overflowing-lsh-3.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to shift left with overflow' // compile-flags: -C debug-assertions -#![warn(exceeding_bitshifts)] +#![warn(arithmetic_overflow)] #![warn(const_err)] fn main() { diff --git a/src/test/run-fail/overflowing-lsh-4.rs b/src/test/run-fail/overflowing-lsh-4.rs index ec304b4144e..0d3912ce13f 100644 --- a/src/test/run-fail/overflowing-lsh-4.rs +++ b/src/test/run-fail/overflowing-lsh-4.rs @@ -4,7 +4,7 @@ // This function is checking that our automatic truncation does not // sidestep the overflow checking. -#![warn(exceeding_bitshifts)] +#![warn(arithmetic_overflow)] #![warn(const_err)] fn main() { diff --git a/src/test/run-fail/overflowing-mul.rs b/src/test/run-fail/overflowing-mul.rs index 48110365a81..2dfc9bb5ae4 100644 --- a/src/test/run-fail/overflowing-mul.rs +++ b/src/test/run-fail/overflowing-mul.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to multiply with overflow' // compile-flags: -C debug-assertions -#![allow(const_err)] +#![allow(arithmetic_overflow)] fn main() { let x = 200u8 * 4; diff --git a/src/test/run-fail/overflowing-neg.rs b/src/test/run-fail/overflowing-neg.rs index c4afd74241e..f512aa35bed 100644 --- a/src/test/run-fail/overflowing-neg.rs +++ b/src/test/run-fail/overflowing-neg.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to negate with overflow' // compile-flags: -C debug-assertions -#![allow(const_err)] +#![allow(arithmetic_overflow)] fn main() { let _x = -std::i8::MIN; diff --git a/src/test/run-fail/overflowing-rsh-1.rs b/src/test/run-fail/overflowing-rsh-1.rs index 14514540c06..4592b2b6260 100644 --- a/src/test/run-fail/overflowing-rsh-1.rs +++ b/src/test/run-fail/overflowing-rsh-1.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions -#![warn(exceeding_bitshifts)] +#![warn(arithmetic_overflow)] #![warn(const_err)] fn main() { diff --git a/src/test/run-fail/overflowing-rsh-2.rs b/src/test/run-fail/overflowing-rsh-2.rs index 83dcbd13d2a..066267b770d 100644 --- a/src/test/run-fail/overflowing-rsh-2.rs +++ b/src/test/run-fail/overflowing-rsh-2.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions -#![warn(exceeding_bitshifts)] +#![warn(arithmetic_overflow)] #![warn(const_err)] fn main() { diff --git a/src/test/run-fail/overflowing-rsh-3.rs b/src/test/run-fail/overflowing-rsh-3.rs index 3521c050659..67e78482866 100644 --- a/src/test/run-fail/overflowing-rsh-3.rs +++ b/src/test/run-fail/overflowing-rsh-3.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions -#![warn(exceeding_bitshifts)] +#![warn(arithmetic_overflow)] #![warn(const_err)] fn main() { diff --git a/src/test/run-fail/overflowing-rsh-4.rs b/src/test/run-fail/overflowing-rsh-4.rs index ed1191849e5..1877d5c9685 100644 --- a/src/test/run-fail/overflowing-rsh-4.rs +++ b/src/test/run-fail/overflowing-rsh-4.rs @@ -4,7 +4,7 @@ // This function is checking that our (type-based) automatic // truncation does not sidestep the overflow checking. -#![warn(exceeding_bitshifts)] +#![warn(arithmetic_overflow)] #![warn(const_err)] fn main() { diff --git a/src/test/run-fail/overflowing-rsh-5.rs b/src/test/run-fail/overflowing-rsh-5.rs index 58dfc5710ae..20ef324a82a 100644 --- a/src/test/run-fail/overflowing-rsh-5.rs +++ b/src/test/run-fail/overflowing-rsh-5.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions -#![warn(exceeding_bitshifts)] +#![warn(arithmetic_overflow)] #![warn(const_err)] fn main() { diff --git a/src/test/run-fail/overflowing-rsh-6.rs b/src/test/run-fail/overflowing-rsh-6.rs index c2fec5e4860..589a98bab04 100644 --- a/src/test/run-fail/overflowing-rsh-6.rs +++ b/src/test/run-fail/overflowing-rsh-6.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to shift right with overflow' // compile-flags: -C debug-assertions -#![warn(exceeding_bitshifts)] +#![warn(arithmetic_overflow)] #![warn(const_err)] #![feature(const_indexing)] diff --git a/src/test/run-fail/overflowing-sub.rs b/src/test/run-fail/overflowing-sub.rs index e3b111dd2bb..fb096c31957 100644 --- a/src/test/run-fail/overflowing-sub.rs +++ b/src/test/run-fail/overflowing-sub.rs @@ -1,7 +1,7 @@ // error-pattern:thread 'main' panicked at 'attempt to subtract with overflow' // compile-flags: -C debug-assertions -#![allow(const_err)] +#![allow(arithmetic_overflow)] fn main() { let _x = 42u8 - (42u8 + 1); diff --git a/src/test/run-fail/promoted_div_by_zero.rs b/src/test/run-fail/promoted_div_by_zero.rs index 3fe51a19c20..dc6719ce025 100644 --- a/src/test/run-fail/promoted_div_by_zero.rs +++ b/src/test/run-fail/promoted_div_by_zero.rs @@ -1,4 +1,4 @@ -#![allow(const_err)] +#![allow(unconditional_panic, const_err)] // error-pattern: attempt to divide by zero diff --git a/src/test/run-fail/promoted_overflow.rs b/src/test/run-fail/promoted_overflow.rs index 139bf540959..3c42da4b1d8 100644 --- a/src/test/run-fail/promoted_overflow.rs +++ b/src/test/run-fail/promoted_overflow.rs @@ -1,4 +1,4 @@ -#![allow(const_err)] +#![allow(arithmetic_overflow)] // error-pattern: overflow // compile-flags: -C overflow-checks=yes diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index 07ef2424cc8..d975af52f5b 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -7,14 +7,12 @@ extern crate rustc_data_structures; extern crate rustc_hir; extern crate rustc_target; extern crate rustc_driver; +extern crate rustc_session; extern crate rustc_span; use std::any::Any; use std::sync::Arc; use std::path::Path; -use rustc_span::symbol::Symbol; -use rustc::session::Session; -use rustc::session::config::OutputFilenames; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; use rustc::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn}; @@ -23,6 +21,9 @@ use rustc::util::common::ErrorReported; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_data_structures::sync::MetadataRef; use rustc_data_structures::owning_ref::OwningRef; +use rustc_session::Session; +use rustc_session::config::OutputFilenames; +use rustc_span::symbol::Symbol; use rustc_target::spec::Target; pub struct NoLlvmMetadataLoader; @@ -89,7 +90,7 @@ impl CodegenBackend for TheBackend { outputs: &OutputFilenames, ) -> Result<(), ErrorReported> { use std::io::Write; - use rustc::session::config::CrateType; + use rustc_session::config::CrateType; use rustc_codegen_utils::link::out_filename; let crate_name = codegen_results.downcast::() .expect("in link: codegen_results is not a Symbol"); diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index 12da64fc88f..af84faa7511 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -1,13 +1,12 @@ #![feature(rustc_private)] -extern crate rustc; extern crate rustc_interface; extern crate rustc_driver; +extern crate rustc_session; extern crate rustc_span; -use rustc::session::DiagnosticOutput; -use rustc::session::config::{Input, Options, - OutputType, OutputTypes}; +use rustc_session::DiagnosticOutput; +use rustc_session::config::{Input, Options, OutputType, OutputTypes}; use rustc_interface::interface; use rustc_span::source_map::FileName; diff --git a/src/test/run-make-fulldeps/issue-68794-textrel-on-minimal-lib/Makefile b/src/test/run-make-fulldeps/issue-68794-textrel-on-minimal-lib/Makefile new file mode 100644 index 00000000000..2f16ad32859 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-68794-textrel-on-minimal-lib/Makefile @@ -0,0 +1,17 @@ +# Regression test for issue #68794 +# +# Verify that no text relocations are accidentally introduced by linking a +# minimal rust staticlib. +# +# The test links a rust static library into a shared library, and checks that +# the linker doesn't have to flag the resulting file as containing TEXTRELs. + +-include ../tools.mk + +# only-linux + +all: + $(RUSTC) foo.rs + $(CC) bar.c $(call STATICLIB,foo) -fPIC -shared -o $(call DYLIB,bar) \ + $(EXTRACFLAGS) $(EXTRACXXFLAGS) + readelf -d $(call DYLIB,bar) | grep TEXTREL; test $$? -eq 1 diff --git a/src/test/run-make-fulldeps/issue-68794-textrel-on-minimal-lib/bar.c b/src/test/run-make-fulldeps/issue-68794-textrel-on-minimal-lib/bar.c new file mode 100644 index 00000000000..bb4036b06e1 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-68794-textrel-on-minimal-lib/bar.c @@ -0,0 +1,6 @@ +void foo(); + +int main() { + foo(); + return 0; +} diff --git a/src/test/run-make-fulldeps/issue-68794-textrel-on-minimal-lib/foo.rs b/src/test/run-make-fulldeps/issue-68794-textrel-on-minimal-lib/foo.rs new file mode 100644 index 00000000000..a3e865b638e --- /dev/null +++ b/src/test/run-make-fulldeps/issue-68794-textrel-on-minimal-lib/foo.rs @@ -0,0 +1,8 @@ +#![crate_type = "staticlib"] + +#[no_mangle] +pub extern "C" fn foo(x: u32) { + // using the println! makes it so that enough code from the standard + // library is included (see issue #68794) + println!("foo: {}", x); +} diff --git a/src/test/run-make-fulldeps/issue-69368/Makefile b/src/test/run-make-fulldeps/issue-69368/Makefile new file mode 100644 index 00000000000..dbb044d8f5d --- /dev/null +++ b/src/test/run-make-fulldeps/issue-69368/Makefile @@ -0,0 +1,18 @@ +-include ../tools.mk + +# Test that previously triggered a linker failure with root cause +# similar to one found in the issue #69368. +# +# The crate that provides oom lang item is missing some other lang +# items. Necessary to prevent the use of start-group / end-group. +# +# The weak lang items are defined in a separate compilation units, +# so that linker could omit them if not used. +# +# The crates that need those weak lang items are dependencies of +# crates that provide them. + +all: + $(RUSTC) a.rs + $(RUSTC) b.rs + $(RUSTC) c.rs diff --git a/src/test/run-make-fulldeps/issue-69368/a.rs b/src/test/run-make-fulldeps/issue-69368/a.rs new file mode 100644 index 00000000000..726db874637 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-69368/a.rs @@ -0,0 +1,16 @@ +#![crate_type = "rlib"] +#![feature(lang_items)] +#![feature(panic_unwind)] +#![no_std] + +extern crate panic_unwind; + +#[panic_handler] +pub fn panic_handler(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[no_mangle] +extern "C" fn __rust_drop_panic() -> ! { + loop {} +} diff --git a/src/test/run-make-fulldeps/issue-69368/b.rs b/src/test/run-make-fulldeps/issue-69368/b.rs new file mode 100644 index 00000000000..4d6af026656 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-69368/b.rs @@ -0,0 +1,8 @@ +#![crate_type = "rlib"] +#![feature(alloc_error_handler)] +#![no_std] + +#[alloc_error_handler] +pub fn error_handler(_: core::alloc::Layout) -> ! { + panic!(); +} diff --git a/src/test/run-make-fulldeps/issue-69368/c.rs b/src/test/run-make-fulldeps/issue-69368/c.rs new file mode 100644 index 00000000000..729c4249a05 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-69368/c.rs @@ -0,0 +1,34 @@ +#![crate_type = "bin"] +#![feature(start)] +#![no_std] + +extern crate alloc; +extern crate a; +extern crate b; + +use alloc::vec::Vec; +use core::alloc::*; + +struct Allocator; + +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, _: Layout) -> *mut u8 { + loop {} + } + + unsafe fn dealloc(&self, _: *mut u8, _: Layout) { + loop {} + } +} + +#[global_allocator] +static ALLOCATOR: Allocator = Allocator; + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + let mut v = Vec::new(); + for i in 0..argc { + v.push(i); + } + v.iter().sum() +} diff --git a/src/test/run-make-fulldeps/min-global-align/min_global_align.rs b/src/test/run-make-fulldeps/min-global-align/min_global_align.rs index ce86d202c62..d9851a2f794 100644 --- a/src/test/run-make-fulldeps/min-global-align/min_global_align.rs +++ b/src/test/run-make-fulldeps/min-global-align/min_global_align.rs @@ -1,5 +1,5 @@ #![feature(no_core, lang_items)] -#![crate_type="rlib"] +#![crate_type = "rlib"] #![no_core] pub static STATIC_BOOL: bool = true; @@ -9,7 +9,6 @@ pub static mut STATIC_MUT_BOOL: bool = true; const CONST_BOOL: bool = true; pub static CONST_BOOL_REF: &'static bool = &CONST_BOOL; - #[lang = "sized"] trait Sized {} @@ -19,10 +18,13 @@ trait Copy {} #[lang = "freeze"] trait Freeze {} +// No `UnsafeCell`, so everything is `Freeze`. +impl Freeze for T {} + #[lang = "sync"] trait Sync {} impl Sync for bool {} impl Sync for &'static bool {} -#[lang="drop_in_place"] -pub unsafe fn drop_in_place(_: *mut T) { } +#[lang = "drop_in_place"] +pub unsafe fn drop_in_place(_: *mut T) {} diff --git a/src/test/rustdoc-js-std/return-specific-literal.js b/src/test/rustdoc-js-std/return-specific-literal.js new file mode 100644 index 00000000000..c7c347240b7 --- /dev/null +++ b/src/test/rustdoc-js-std/return-specific-literal.js @@ -0,0 +1,10 @@ +const QUERY = 'struct:"string"'; + +const EXPECTED = { + 'in_args': [ + { 'path': 'std::string::String', 'name': 'ne' }, + ], + 'returned': [ + { 'path': 'std::string::String', 'name': 'add' }, + ], +}; diff --git a/src/test/rustdoc-js-std/return-specific.js b/src/test/rustdoc-js-std/return-specific.js new file mode 100644 index 00000000000..d9a910553b8 --- /dev/null +++ b/src/test/rustdoc-js-std/return-specific.js @@ -0,0 +1,10 @@ +const QUERY = 'struct:string'; + +const EXPECTED = { + 'in_args': [ + { 'path': 'std::string::String', 'name': 'ne' }, + ], + 'returned': [ + { 'path': 'std::string::String', 'name': 'add' }, + ], +}; diff --git a/src/test/rustdoc-js/struct-like-variant.js b/src/test/rustdoc-js/struct-like-variant.js new file mode 100644 index 00000000000..f6deea51e7d --- /dev/null +++ b/src/test/rustdoc-js/struct-like-variant.js @@ -0,0 +1,7 @@ +const QUERY = 'name'; + +const EXPECTED = { + 'others': [ + { 'path': 'struct_like_variant::Enum::Bar', 'name': 'name', 'desc': 'This is a name.' }, + ], +}; diff --git a/src/test/rustdoc-js/struct-like-variant.rs b/src/test/rustdoc-js/struct-like-variant.rs new file mode 100644 index 00000000000..2f52a319ab9 --- /dev/null +++ b/src/test/rustdoc-js/struct-like-variant.rs @@ -0,0 +1,8 @@ +#![crate_name = "struct_like_variant"] + +pub enum Enum { + Bar { + /// This is a name. + name: String + } +} diff --git a/src/test/rustdoc-ui/coverage/html.rs b/src/test/rustdoc-ui/coverage/html.rs new file mode 100644 index 00000000000..181cb4c5061 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/html.rs @@ -0,0 +1,4 @@ +// compile-flags:-Z unstable-options --output-format html --show-coverage + +/// Foo +pub struct Xo; diff --git a/src/test/rustdoc-ui/coverage/html.stderr b/src/test/rustdoc-ui/coverage/html.stderr new file mode 100644 index 00000000000..adca375d4bc --- /dev/null +++ b/src/test/rustdoc-ui/coverage/html.stderr @@ -0,0 +1,2 @@ +error: html output format isn't supported for the --show-coverage option + diff --git a/src/test/rustdoc-ui/coverage/json.rs b/src/test/rustdoc-ui/coverage/json.rs new file mode 100644 index 00000000000..b1220b32e91 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/json.rs @@ -0,0 +1,27 @@ +// build-pass +// compile-flags:-Z unstable-options --output-format json --show-coverage + +pub mod foo { + /// Hello! + pub struct Foo; + /// Bar + pub enum Bar { A } +} + +/// X +pub struct X; + +/// Bar +pub mod bar { + /// bar + pub struct Bar; + /// X + pub enum X { Y } +} + +/// yolo +pub enum Yolo { X } + +pub struct Xo { + x: T, +} diff --git a/src/test/rustdoc-ui/coverage/json.stdout b/src/test/rustdoc-ui/coverage/json.stdout new file mode 100644 index 00000000000..63b22a7d94b --- /dev/null +++ b/src/test/rustdoc-ui/coverage/json.stdout @@ -0,0 +1 @@ +{"$DIR/json.rs":{"total":13,"with_docs":7}} diff --git a/src/test/rustdoc-ui/issue-61732.rs b/src/test/rustdoc-ui/issue-61732.rs index d4835c09224..4bd8efeaa3b 100644 --- a/src/test/rustdoc-ui/issue-61732.rs +++ b/src/test/rustdoc-ui/issue-61732.rs @@ -1,4 +1,4 @@ // This previously triggered an ICE. pub(in crate::r#mod) fn main() {} -//~^ ERROR expected module, found unresolved item +//~^ ERROR failed to resolve: maybe a missing crate `r#mod` diff --git a/src/test/rustdoc-ui/issue-61732.stderr b/src/test/rustdoc-ui/issue-61732.stderr index 6c8ba48864d..82134224911 100644 --- a/src/test/rustdoc-ui/issue-61732.stderr +++ b/src/test/rustdoc-ui/issue-61732.stderr @@ -1,11 +1,11 @@ -error[E0577]: expected module, found unresolved item `crate::r#mod` - --> $DIR/issue-61732.rs:3:8 +error[E0433]: failed to resolve: maybe a missing crate `r#mod`? + --> $DIR/issue-61732.rs:3:15 | LL | pub(in crate::r#mod) fn main() {} - | ^^^^^^^^^^^^ not a module + | ^^^^^ maybe a missing crate `r#mod`? error: Compilation failed, aborting rustdoc error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0577`. +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc/attributes.rs b/src/test/rustdoc/attributes.rs index 6ecdad3ec00..e9cd3514a07 100644 --- a/src/test/rustdoc/attributes.rs +++ b/src/test/rustdoc/attributes.rs @@ -15,3 +15,7 @@ pub extern "C" fn g() {} pub enum Foo { Bar, } + +// @has foo/struct.Repr.html '//*[@class="docblock attributes top-attr"]' '#[repr(C, align(8))]' +#[repr(C, align(8))] +pub struct Repr; diff --git a/src/test/rustdoc/comment-in-doctest.rs b/src/test/rustdoc/comment-in-doctest.rs index e4e41bc7ce3..5691d173569 100644 --- a/src/test/rustdoc/comment-in-doctest.rs +++ b/src/test/rustdoc/comment-in-doctest.rs @@ -1,7 +1,7 @@ // compile-flags:--test // comments, both doc comments and regular ones, used to trick rustdoc's doctest parser into -// thinking that everything after it was part of the regular program. combined with the libsyntax +// thinking that everything after it was part of the regular program. combined with the librustc_ast // parser loop failing to detect the manual main function, it would wrap everything in `fn main`, // which would cause the doctest to fail as the "extern crate" declaration was no longer valid. // oddly enough, it would pass in 2018 if a crate was in the extern prelude. see diff --git a/src/test/rustdoc/crate-version-escape.rs b/src/test/rustdoc/crate-version-escape.rs new file mode 100644 index 00000000000..2f91eea339b --- /dev/null +++ b/src/test/rustdoc/crate-version-escape.rs @@ -0,0 +1,6 @@ +// compile-flags: --crate-version= -Z unstable-options + +#![crate_name = "foo"] + +// @has 'foo/index.html' '//div[@class="block version"]/p' 'Version ' +// @has 'foo/all.html' '//div[@class="block version"]/p' 'Version ' diff --git a/src/test/rustdoc/doc-spotlight.rs b/src/test/rustdoc/doc-spotlight.rs deleted file mode 100644 index ddd46c3c215..00000000000 --- a/src/test/rustdoc/doc-spotlight.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![feature(doc_spotlight)] - -pub struct Wrapper { - inner: T, -} - -impl SomeTrait for Wrapper {} - -#[doc(spotlight)] -pub trait SomeTrait { - // @has doc_spotlight/trait.SomeTrait.html - // @has - '//code[@class="content"]' 'impl SomeTrait for Wrapper' - fn wrap_me(self) -> Wrapper where Self: Sized { - Wrapper { - inner: self, - } - } -} - -pub struct SomeStruct; -impl SomeTrait for SomeStruct {} - -impl SomeStruct { - // @has doc_spotlight/struct.SomeStruct.html - // @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' - // @has - '//code[@class="content"]' 'impl SomeTrait for Wrapper' - pub fn new() -> SomeStruct { - SomeStruct - } -} - -// @has doc_spotlight/fn.bare_fn.html -// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' -pub fn bare_fn() -> SomeStruct { - SomeStruct -} diff --git a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs index 37465ccf1c2..d8e5746f3f6 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs @@ -9,6 +9,19 @@ extern crate proc_macro; use proc_macro::TokenStream; +macro_rules! make_attr_macro { + ($name:ident) => { + /// Generated doc comment + #[proc_macro_attribute] + pub fn $name(args: TokenStream, input: TokenStream) -> TokenStream { + panic!() + } + } +} + +make_attr_macro!(first_attr); +make_attr_macro!(second_attr); + /// a proc-macro that swallows its input and does nothing. #[proc_macro] pub fn some_proc_macro(_input: TokenStream) -> TokenStream { diff --git a/src/test/rustdoc/inline_cross/proc_macro.rs b/src/test/rustdoc/inline_cross/proc_macro.rs index 3dc8de3fe57..532a295c0f3 100644 --- a/src/test/rustdoc/inline_cross/proc_macro.rs +++ b/src/test/rustdoc/inline_cross/proc_macro.rs @@ -26,3 +26,11 @@ pub use some_macros::some_proc_attr; // @has proc_macro/derive.SomeDerive.html // @has - 'a derive attribute that adds nothing to its input.' pub use some_macros::SomeDerive; + +// @has proc_macro/attr.first_attr.html +// @has - 'Generated doc comment' +pub use some_macros::first_attr; + +// @has proc_macro/attr.second_attr.html +// @has - 'Generated doc comment' +pub use some_macros::second_attr; diff --git a/src/test/rustdoc/issue-26606.rs b/src/test/rustdoc/issue-26606.rs index 6de419ec571..d2aa4bbbd12 100644 --- a/src/test/rustdoc/issue-26606.rs +++ b/src/test/rustdoc/issue-26606.rs @@ -7,5 +7,5 @@ extern crate issue_26606_macro; // @has issue_26606/constant.FOO.html -// @!has - '//a/@href' '../src/' +// @has - '//a/@href' '../src/issue_26606/auxiliary/issue-26606-macro.rs.html#3' make_item!(FOO); diff --git a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs index 91b3372e8f4..1b6a38acb1c 100644 --- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs +++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs @@ -9,7 +9,7 @@ extern crate rustc_lint; #[macro_use] extern crate rustc_session; extern crate rustc_span; -extern crate syntax; +extern crate rustc_ast; use rustc_ast_pretty::pprust; use rustc_driver::plugin::Registry; diff --git a/src/test/ui-fulldeps/auxiliary/linkage-visibility.rs b/src/test/ui-fulldeps/auxiliary/linkage-visibility.rs index 8917693d45e..837ed1f002f 100644 --- a/src/test/ui-fulldeps/auxiliary/linkage-visibility.rs +++ b/src/test/ui-fulldeps/auxiliary/linkage-visibility.rs @@ -2,16 +2,14 @@ #![feature(rustc_private)] -// We're testing linkage visibility; the compiler warns us, but we want to -// do the runtime check that these functions aren't exported. -#![allow(private_no_mangle_fns)] - extern crate rustc_metadata; use rustc_metadata::dynamic_lib::DynamicLibrary; #[no_mangle] -pub fn foo() { bar(); } +pub fn foo() { + bar(); +} pub fn foo2() { fn bar2() { @@ -21,11 +19,11 @@ pub fn foo2() { } #[no_mangle] -fn bar() { } +fn bar() {} #[allow(dead_code)] #[no_mangle] -fn baz() { } +fn baz() {} pub fn test() { let lib = DynamicLibrary::open(None).unwrap(); diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs index eb251a0a3ad..52620b2464b 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs @@ -9,12 +9,12 @@ extern crate rustc_span; extern crate rustc_lint; #[macro_use] extern crate rustc_session; -extern crate syntax; +extern crate rustc_ast; use rustc_driver::plugin::Registry; use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass}; use rustc_span::symbol::Symbol; -use syntax::attr; +use rustc_ast::attr; macro_rules! fake_lint_pass { ($struct:ident, $($attr:expr),*) => { @@ -29,10 +29,10 @@ macro_rules! fake_lint_pass { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $struct { fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) { $( - if !attr::contains_name(&krate.attrs, $attr) { + if !attr::contains_name(&krate.item.attrs, $attr) { cx.lint(CRATE_NOT_OKAY, |lint| { let msg = format!("crate is not marked with #![{}]", $attr); - lint.build(&msg).set_span(krate.span).emit() + lint.build(&msg).set_span(krate.item.span).emit() }); } )* diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs index e5f4bf88d57..6978d02c09d 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -10,12 +10,12 @@ extern crate rustc_lint; #[macro_use] extern crate rustc_session; extern crate rustc_span; -extern crate syntax; +extern crate rustc_ast; use rustc_driver::plugin::Registry; use rustc_lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass}; use rustc_span::symbol::Symbol; -use syntax::attr; +use rustc_ast::attr; declare_lint! { CRATE_NOT_OKAY, @@ -27,10 +27,10 @@ declare_lint_pass!(Pass => [CRATE_NOT_OKAY]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) { - if !attr::contains_name(&krate.attrs, Symbol::intern("crate_okay")) { + if !attr::contains_name(&krate.item.attrs, Symbol::intern("crate_okay")) { cx.lint(CRATE_NOT_OKAY, |lint| { lint.build("crate is not marked with #![crate_okay]") - .set_span(krate.span) + .set_span(krate.item.span) .emit() }); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs index ad5f882c434..bb2a4d03734 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs @@ -3,7 +3,7 @@ #![feature(plugin_registrar)] #![feature(box_syntax, rustc_private)] -extern crate syntax; +extern crate rustc_ast; // Load rustc as a plugin to get macros extern crate rustc_driver; @@ -14,7 +14,7 @@ extern crate rustc_session; use rustc_driver::plugin::Registry; use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; -use syntax::ast; +use rustc_ast::ast; declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); declare_lint_pass!(Pass => [TEST_LINT]); diff --git a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs index b14dbdf8f93..8c517e2bb5d 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs @@ -1,7 +1,7 @@ #![feature(plugin_registrar)] #![feature(box_syntax, rustc_private)] -extern crate syntax; +extern crate rustc_ast; // Load rustc as a plugin to get macros extern crate rustc_driver; @@ -12,7 +12,7 @@ extern crate rustc_session; use rustc_driver::plugin::Registry; use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintId, LintPass}; -use syntax::ast; +use rustc_ast::ast; declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff"); declare_tool_lint!( /// Some docs diff --git a/src/test/ui-fulldeps/auxiliary/macro-crate-test.rs b/src/test/ui-fulldeps/auxiliary/macro-crate-test.rs index fa136fd54c2..56a560acbb4 100644 --- a/src/test/ui-fulldeps/auxiliary/macro-crate-test.rs +++ b/src/test/ui-fulldeps/auxiliary/macro-crate-test.rs @@ -4,7 +4,7 @@ #![crate_type = "proc-macro"] #![feature(rustc_private)] -extern crate syntax; +extern crate rustc_ast; extern crate rustc; extern crate rustc_driver; extern crate proc_macro; diff --git a/src/test/ui-fulldeps/lint-group-denied-lint-allowed.rs b/src/test/ui-fulldeps/lint-group-denied-lint-allowed.rs new file mode 100644 index 00000000000..7498745f206 --- /dev/null +++ b/src/test/ui-fulldeps/lint-group-denied-lint-allowed.rs @@ -0,0 +1,7 @@ +// aux-build:lint-group-plugin-test.rs +// check-pass +// compile-flags: -D unused -A unused-variables + +fn main() { + let x = 1; +} diff --git a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs index be4b49ada02..1046355a343 100644 --- a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -1,10 +1,10 @@ // run-pass -// Testing that a libsyntax can parse modules with canonicalized base path +// Testing that a librustc_ast can parse modules with canonicalized base path // ignore-cross-compile #![feature(rustc_private)] -extern crate syntax; +extern crate rustc_ast; extern crate rustc_parse; extern crate rustc_session; extern crate rustc_span; @@ -18,7 +18,7 @@ use std::path::Path; mod gravy; pub fn main() { - syntax::with_default_globals(|| parse()); + rustc_ast::with_default_globals(|| parse()); assert_eq!(gravy::foo(), 10); } diff --git a/src/test/ui-fulldeps/plugin-as-extern-crate.rs b/src/test/ui-fulldeps/plugin-as-extern-crate.rs index f231efc0a9a..4d26e08d81e 100644 --- a/src/test/ui-fulldeps/plugin-as-extern-crate.rs +++ b/src/test/ui-fulldeps/plugin-as-extern-crate.rs @@ -3,7 +3,7 @@ // ignore-cross-compile // // empty_plugin will not compile on a cross-compiled target because -// libsyntax is not compiled for it. +// librustc_ast is not compiled for it. extern crate empty_plugin; // OK, plugin crates are still crates diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 7ac75c605f2..365ae301c0f 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -21,7 +21,7 @@ extern crate rustc_ast_pretty; extern crate rustc_data_structures; -extern crate syntax; +extern crate rustc_ast; extern crate rustc_parse; extern crate rustc_session; extern crate rustc_span; @@ -32,9 +32,9 @@ use rustc_parse::new_parser_from_source_str; use rustc_session::parse::ParseSess; use rustc_span::source_map::{Spanned, DUMMY_SP, FileName}; use rustc_span::source_map::FilePathMapping; -use syntax::ast::*; -use syntax::mut_visit::{self, MutVisitor, visit_clobber}; -use syntax::ptr::P; +use rustc_ast::ast::*; +use rustc_ast::mut_visit::{self, MutVisitor, visit_clobber}; +use rustc_ast::ptr::P; fn parse_expr(ps: &ParseSess, src: &str) -> Option> { let src_as_string = src.to_string(); @@ -117,7 +117,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { 11 => { let decl = P(FnDecl { inputs: vec![], - output: FunctionRetTy::Default(DUMMY_SP), + output: FnRetTy::Default(DUMMY_SP), }); iter_exprs(depth - 1, &mut |e| g( ExprKind::Closure(CaptureBy::Value, @@ -205,7 +205,7 @@ impl MutVisitor for AddParens { } fn main() { - syntax::with_default_globals(|| run()); + rustc_ast::with_default_globals(|| run()); } fn run() { diff --git a/src/test/ui/allocator/custom.rs b/src/test/ui/allocator/custom.rs index 0b1f6d5a96e..c275db14b42 100644 --- a/src/test/ui/allocator/custom.rs +++ b/src/test/ui/allocator/custom.rs @@ -37,7 +37,7 @@ fn main() { unsafe { let layout = Layout::from_size_align(4, 2).unwrap(); - let ptr = Global.alloc(layout.clone()).unwrap(); + let (ptr, _) = Global.alloc(layout.clone()).unwrap(); helper::work_with(&ptr); assert_eq!(HITS.load(Ordering::SeqCst), n + 1); Global.dealloc(ptr, layout.clone()); @@ -49,7 +49,7 @@ fn main() { drop(s); assert_eq!(HITS.load(Ordering::SeqCst), n + 4); - let ptr = System.alloc(layout.clone()).unwrap(); + let (ptr, _) = System.alloc(layout.clone()).unwrap(); assert_eq!(HITS.load(Ordering::SeqCst), n + 4); helper::work_with(&ptr); System.dealloc(ptr, layout); diff --git a/src/test/ui/allocator/xcrate-use.rs b/src/test/ui/allocator/xcrate-use.rs index 37b28c195df..e4746d1a7ec 100644 --- a/src/test/ui/allocator/xcrate-use.rs +++ b/src/test/ui/allocator/xcrate-use.rs @@ -20,13 +20,13 @@ fn main() { let n = GLOBAL.0.load(Ordering::SeqCst); let layout = Layout::from_size_align(4, 2).unwrap(); - let ptr = Global.alloc(layout.clone()).unwrap(); + let (ptr, _) = Global.alloc(layout.clone()).unwrap(); helper::work_with(&ptr); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1); Global.dealloc(ptr, layout.clone()); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); - let ptr = System.alloc(layout.clone()).unwrap(); + let (ptr, _) = System.alloc(layout.clone()).unwrap(); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); helper::work_with(&ptr); System.dealloc(ptr, layout); diff --git a/src/test/ui/anon-params-denied-2018.rs b/src/test/ui/anon-params/anon-params-denied-2018.rs similarity index 100% rename from src/test/ui/anon-params-denied-2018.rs rename to src/test/ui/anon-params/anon-params-denied-2018.rs diff --git a/src/test/ui/anon-params-denied-2018.stderr b/src/test/ui/anon-params/anon-params-denied-2018.stderr similarity index 100% rename from src/test/ui/anon-params-denied-2018.stderr rename to src/test/ui/anon-params/anon-params-denied-2018.stderr diff --git a/src/test/ui/anon-params-deprecated.fixed b/src/test/ui/anon-params/anon-params-deprecated.fixed similarity index 100% rename from src/test/ui/anon-params-deprecated.fixed rename to src/test/ui/anon-params/anon-params-deprecated.fixed diff --git a/src/test/ui/anon-params-deprecated.rs b/src/test/ui/anon-params/anon-params-deprecated.rs similarity index 100% rename from src/test/ui/anon-params-deprecated.rs rename to src/test/ui/anon-params/anon-params-deprecated.rs diff --git a/src/test/ui/anon-params-deprecated.stderr b/src/test/ui/anon-params/anon-params-deprecated.stderr similarity index 100% rename from src/test/ui/anon-params-deprecated.stderr rename to src/test/ui/anon-params/anon-params-deprecated.stderr diff --git a/src/test/ui/anon-params/anon-params-edition-hygiene.rs b/src/test/ui/anon-params/anon-params-edition-hygiene.rs new file mode 100644 index 00000000000..14e11c5696f --- /dev/null +++ b/src/test/ui/anon-params/anon-params-edition-hygiene.rs @@ -0,0 +1,10 @@ +// check-pass +// edition:2018 +// aux-build:anon-params-edition-hygiene.rs + +#[macro_use] +extern crate anon_params_edition_hygiene; + +generate_trait_2015!(u8); + +fn main() {} diff --git a/src/test/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs b/src/test/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs new file mode 100644 index 00000000000..aa4221becc2 --- /dev/null +++ b/src/test/ui/anon-params/auxiliary/anon-params-edition-hygiene.rs @@ -0,0 +1,12 @@ +// edition:2015 + +#[macro_export] +macro_rules! generate_trait_2015 { + ($Type: ident) => { + trait Trait { + fn method($Type) {} + } + }; +} + +fn main() {} diff --git a/src/test/ui/arg-count-mismatch.rs b/src/test/ui/arg-count-mismatch.rs index cf7487069c1..18926f5daf7 100644 --- a/src/test/ui/arg-count-mismatch.rs +++ b/src/test/ui/arg-count-mismatch.rs @@ -1,4 +1,4 @@ -// error-pattern: parameters were supplied +// error-pattern: arguments were supplied fn f(x: isize) { } diff --git a/src/test/ui/arg-count-mismatch.stderr b/src/test/ui/arg-count-mismatch.stderr index 44f16041363..7bc06134a69 100644 --- a/src/test/ui/arg-count-mismatch.stderr +++ b/src/test/ui/arg-count-mismatch.stderr @@ -1,11 +1,13 @@ -error[E0061]: this function takes 1 parameter but 0 parameters were supplied +error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/arg-count-mismatch.rs:5:28 | LL | fn f(x: isize) { } | -------------- defined here LL | LL | fn main() { let i: (); i = f(); } - | ^^^ expected 1 parameter + | ^-- supplied 0 arguments + | | + | expected 1 argument error: aborting due to previous error diff --git a/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs b/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs new file mode 100644 index 00000000000..061b0d675b3 --- /dev/null +++ b/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.rs @@ -0,0 +1,18 @@ +// We used to not lower the extra `b @ ..` into `b @ _` which meant that no type +// was registered for the binding `b` although it passed through resolve. +// This resulted in an ICE (#69103). + +fn main() { + let [a @ .., b @ ..] = &mut [1, 2]; + //~^ ERROR `..` can only be used once per slice pattern + b; + + let [.., c @ ..] = [1, 2]; + //~^ ERROR `..` can only be used once per slice pattern + c; + + // This never ICEd, but let's make sure it won't regress either. + let (.., d @ ..) = (1, 2); + //~^ ERROR `..` patterns are not allowed here + d; +} diff --git a/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.stderr b/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.stderr new file mode 100644 index 00000000000..9432e2f0c9d --- /dev/null +++ b/src/test/ui/array-slice-vec/issue-69103-extra-binding-subslice.stderr @@ -0,0 +1,26 @@ +error: `..` can only be used once per slice pattern + --> $DIR/issue-69103-extra-binding-subslice.rs:6:22 + | +LL | let [a @ .., b @ ..] = &mut [1, 2]; + | -- ^^ can only be used once per slice pattern + | | + | previously used here + +error: `..` can only be used once per slice pattern + --> $DIR/issue-69103-extra-binding-subslice.rs:10:18 + | +LL | let [.., c @ ..] = [1, 2]; + | -- ^^ can only be used once per slice pattern + | | + | previously used here + +error: `..` patterns are not allowed here + --> $DIR/issue-69103-extra-binding-subslice.rs:15:18 + | +LL | let (.., d @ ..) = (1, 2); + | ^^ + | + = note: only allowed in tuple, tuple struct, and slice patterns + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/asm/issue-62046.rs b/src/test/ui/asm/issue-62046.rs new file mode 100644 index 00000000000..105dadd5fd3 --- /dev/null +++ b/src/test/ui/asm/issue-62046.rs @@ -0,0 +1,11 @@ +// build-fail +// ignore-emscripten no asm! support + +#![feature(asm)] + +fn main() { + unsafe { + asm!("nop" : "+r"("r15")); + //~^ malformed inline assembly + } +} diff --git a/src/test/ui/asm/issue-62046.stderr b/src/test/ui/asm/issue-62046.stderr new file mode 100644 index 00000000000..a38a300548d --- /dev/null +++ b/src/test/ui/asm/issue-62046.stderr @@ -0,0 +1,11 @@ +error[E0668]: malformed inline assembly + --> $DIR/issue-62046.rs:8:9 + | +LL | asm!("nop" : "+r"("r15")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0668`. diff --git a/src/test/ui/asm/issue-69092.rs b/src/test/ui/asm/issue-69092.rs new file mode 100644 index 00000000000..caa5c2e0b9f --- /dev/null +++ b/src/test/ui/asm/issue-69092.rs @@ -0,0 +1,10 @@ +// build-fail +// ignore-emscripten no asm! support +// Regression test for #69092 + +#![feature(asm)] + +fn main() { + unsafe { asm!(".ascii \"Xen\0\""); } + //~^ ERROR: :1:9: error: expected string in '.ascii' directive +} diff --git a/src/test/ui/asm/issue-69092.stderr b/src/test/ui/asm/issue-69092.stderr new file mode 100644 index 00000000000..5661097cb8b --- /dev/null +++ b/src/test/ui/asm/issue-69092.stderr @@ -0,0 +1,11 @@ +error: :1:9: error: expected string in '.ascii' directive + .ascii "Xen + ^ + + --> $DIR/issue-69092.rs:8:14 + | +LL | unsafe { asm!(".ascii \"Xen\0\""); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/assign-to-method.rs b/src/test/ui/assign-to-method.rs deleted file mode 100644 index 95f066c382c..00000000000 --- a/src/test/ui/assign-to-method.rs +++ /dev/null @@ -1,22 +0,0 @@ -struct Cat { - meows : usize, - - how_hungry : isize, -} - -impl Cat { - pub fn speak(&self) { self.meows += 1; } -} - -fn cat(in_x : usize, in_y : isize) -> Cat { - Cat { - meows: in_x, - how_hungry: in_y - } -} - -fn main() { - let nyan : Cat = cat(52, 99); - nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method - nyan.speak += || println!("meow"); //~ ERROR attempted to take value of method -} diff --git a/src/test/ui/associated-const/associated-const-no-item.stderr b/src/test/ui/associated-const/associated-const-no-item.stderr index d96cf67b875..fe27da5ac64 100644 --- a/src/test/ui/associated-const/associated-const-no-item.stderr +++ b/src/test/ui/associated-const/associated-const-no-item.stderr @@ -5,8 +5,11 @@ LL | const X: i32 = ::ID; | ^^ associated item not found in `i32` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `ID`, perhaps you need to implement it: - candidate #1: `Foo` +note: `Foo` defines an item `ID`, perhaps you need to implement it + --> $DIR/associated-const-no-item.rs:1:1 + | +LL | trait Foo { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.rs b/src/test/ui/associated-const/defaults-cyclic-fail.rs new file mode 100644 index 00000000000..9b899ee316a --- /dev/null +++ b/src/test/ui/associated-const/defaults-cyclic-fail.rs @@ -0,0 +1,17 @@ +// build-fail + +// Cyclic assoc. const defaults don't error unless *used* +trait Tr { + const A: u8 = Self::B; + //~^ ERROR cycle detected when const-evaluating + checking `Tr::A` + + const B: u8 = Self::A; +} + +// This impl is *allowed* unless its assoc. consts are used +impl Tr for () {} + +fn main() { + // This triggers the cycle error + assert_eq!(<() as Tr>::A, 0); +} diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.stderr b/src/test/ui/associated-const/defaults-cyclic-fail.stderr new file mode 100644 index 00000000000..940182d4aa6 --- /dev/null +++ b/src/test/ui/associated-const/defaults-cyclic-fail.stderr @@ -0,0 +1,31 @@ +error[E0391]: cycle detected when const-evaluating + checking `Tr::A` + --> $DIR/defaults-cyclic-fail.rs:5:5 + | +LL | const A: u8 = Self::B; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating `Tr::A`... + --> $DIR/defaults-cyclic-fail.rs:5:19 + | +LL | const A: u8 = Self::B; + | ^^^^^^^ +note: ...which requires const-evaluating + checking `Tr::B`... + --> $DIR/defaults-cyclic-fail.rs:8:5 + | +LL | const B: u8 = Self::A; + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires const-evaluating `Tr::B`... + --> $DIR/defaults-cyclic-fail.rs:8:19 + | +LL | const B: u8 = Self::A; + | ^^^^^^^ + = note: ...which again requires const-evaluating + checking `Tr::A`, completing the cycle +note: cycle used when const-evaluating `main` + --> $DIR/defaults-cyclic-fail.rs:16:16 + | +LL | assert_eq!(<() as Tr>::A, 0); + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/associated-const/defaults-cyclic-pass.rs b/src/test/ui/associated-const/defaults-cyclic-pass.rs new file mode 100644 index 00000000000..82105f25f92 --- /dev/null +++ b/src/test/ui/associated-const/defaults-cyclic-pass.rs @@ -0,0 +1,36 @@ +// run-pass + +// Cyclic assoc. const defaults don't error unless *used* +trait Tr { + const A: u8 = Self::B; + const B: u8 = Self::A; +} + +// This impl is *allowed* unless its assoc. consts are used, matching the +// behavior without defaults. +impl Tr for () {} + +// Overriding either constant breaks the cycle +impl Tr for u8 { + const A: u8 = 42; +} + +impl Tr for u16 { + const B: u8 = 0; +} + +impl Tr for u32 { + const A: u8 = 100; + const B: u8 = 123; +} + +fn main() { + assert_eq!(::A, 42); + assert_eq!(::B, 42); + + assert_eq!(::A, 0); + assert_eq!(::B, 0); + + assert_eq!(::A, 100); + assert_eq!(::B, 123); +} diff --git a/src/test/ui/associated-const/defaults-not-assumed-fail.rs b/src/test/ui/associated-const/defaults-not-assumed-fail.rs new file mode 100644 index 00000000000..d7a48cbd63e --- /dev/null +++ b/src/test/ui/associated-const/defaults-not-assumed-fail.rs @@ -0,0 +1,45 @@ +// build-fail + +trait Tr { + const A: u8 = 255; + + // This should not be a constant evaluation error (overflow). The value of + // `Self::A` must not be assumed to hold inside the trait. + const B: u8 = Self::A + 1; + //~^ ERROR any use of this value will cause an error +} + +// An impl that doesn't override any constant will NOT cause a const eval error +// just because it's defined, but only if the bad constant is used anywhere. +// This matches the behavior without defaults. +impl Tr for () {} + +// An impl that overrides either constant with a suitable value will be fine. +impl Tr for u8 { + const A: u8 = 254; +} + +impl Tr for u16 { + const B: u8 = 0; +} + +impl Tr for u32 { + const A: u8 = 254; + const B: u8 = 0; +} + +fn main() { + assert_eq!(<() as Tr>::A, 255); + assert_eq!(<() as Tr>::B, 0); // causes the error above + //~^ ERROR evaluation of constant expression failed + //~| ERROR erroneous constant used + + assert_eq!(::A, 254); + assert_eq!(::B, 255); + + assert_eq!(::A, 255); + assert_eq!(::B, 0); + + assert_eq!(::A, 254); + assert_eq!(::B, 0); +} diff --git a/src/test/ui/associated-const/defaults-not-assumed-fail.stderr b/src/test/ui/associated-const/defaults-not-assumed-fail.stderr new file mode 100644 index 00000000000..fe3721a9109 --- /dev/null +++ b/src/test/ui/associated-const/defaults-not-assumed-fail.stderr @@ -0,0 +1,31 @@ +error: any use of this value will cause an error + --> $DIR/defaults-not-assumed-fail.rs:8:19 + | +LL | const B: u8 = Self::A + 1; + | --------------^^^^^^^^^^^- + | | + | attempt to add with overflow + | + = note: `#[deny(const_err)]` on by default + +error[E0080]: evaluation of constant expression failed + --> $DIR/defaults-not-assumed-fail.rs:33:5 + | +LL | assert_eq!(<() as Tr>::B, 0); // causes the error above + | ^^^^^^^^^^^-------------^^^^^ + | | + | referenced constant has errors + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: erroneous constant used + --> $DIR/defaults-not-assumed-fail.rs:33:5 + | +LL | assert_eq!(<() as Tr>::B, 0); // causes the error above + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/associated-const/defaults-not-assumed-pass.rs b/src/test/ui/associated-const/defaults-not-assumed-pass.rs new file mode 100644 index 00000000000..c08e05c8a30 --- /dev/null +++ b/src/test/ui/associated-const/defaults-not-assumed-pass.rs @@ -0,0 +1,42 @@ +// run-pass + +trait Tr { + const A: u8 = 255; + + // This should not be a constant evaluation error (overflow). The value of + // `Self::A` must not be assumed to hold inside the trait. + const B: u8 = Self::A + 1; +} + +// An impl that doesn't override any constant will NOT cause a const eval error +// just because it's defined, but only if the bad constant is used anywhere. +// This matches the behavior without defaults. +impl Tr for () {} + +// An impl that overrides either constant with a suitable value will be fine. +impl Tr for u8 { + const A: u8 = 254; +} + +impl Tr for u16 { + const B: u8 = 0; +} + +impl Tr for u32 { + const A: u8 = 254; + const B: u8 = 0; +} + +fn main() { + assert_eq!(<() as Tr>::A, 255); + //assert_eq!(<() as Tr>::B, 0); // using this is an error + + assert_eq!(::A, 254); + assert_eq!(::B, 255); + + assert_eq!(::A, 255); + assert_eq!(::B, 0); + + assert_eq!(::A, 254); + assert_eq!(::B, 0); +} diff --git a/src/test/ui/associated-item/associated-item-enum.stderr b/src/test/ui/associated-item/associated-item-enum.stderr index 6f89530eac9..cadf55454a7 100644 --- a/src/test/ui/associated-item/associated-item-enum.stderr +++ b/src/test/ui/associated-item/associated-item-enum.stderr @@ -8,7 +8,7 @@ LL | Enum::mispellable(); | ^^^^^^^^^^^ | | | variant or associated item not found in `Enum` - | help: there is a method with a similar name: `misspellable` + | help: there is an associated function with a similar name: `misspellable` error[E0599]: no variant or associated item named `mispellable_trait` found for enum `Enum` in the current scope --> $DIR/associated-item-enum.rs:18:11 diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr index df1151d876c..82b2d32d09d 100644 --- a/src/test/ui/associated-type-bounds/duplicate.stderr +++ b/src/test/ui/associated-type-bounds/duplicate.stderr @@ -728,3 +728,4 @@ LL | type TADyn3 = dyn Iterator; error: aborting due to 96 previous errors +For more information about this error, try `rustc --explain E0719`. diff --git a/src/test/ui/associated-types/associated-types-overridden-default.rs b/src/test/ui/associated-types/associated-types-overridden-default.rs index 629fc7a7668..3e12c922896 100644 --- a/src/test/ui/associated-types/associated-types-overridden-default.rs +++ b/src/test/ui/associated-types/associated-types-overridden-default.rs @@ -1,3 +1,8 @@ +// check-pass + +// Before RFC 2532, overriding one assoc. type default required overriding all +// provided defaults. + #![feature(associated_type_defaults)] pub trait Tr { @@ -9,7 +14,9 @@ pub trait Tr { impl Tr for () { type Assoc = (); - //~^ ERROR need to be reimplemented as `Assoc` was overridden: `Assoc2`, `C`, `foo` } -fn main() {} +fn main() { + let _: <() as Tr>::Assoc = (); + let _: <() as Tr>::Assoc2 = (); +} diff --git a/src/test/ui/associated-types/associated-types-overridden-default.stderr b/src/test/ui/associated-types/associated-types-overridden-default.stderr deleted file mode 100644 index 79fb9a613c2..00000000000 --- a/src/test/ui/associated-types/associated-types-overridden-default.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0399]: the following trait items need to be reimplemented as `Assoc` was overridden: `Assoc2`, `C`, `foo` - --> $DIR/associated-types-overridden-default.rs:11:5 - | -LL | type Assoc = (); - | ^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0399`. diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs index 8a5777d4d7c..58f186d7775 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.rs @@ -12,11 +12,12 @@ struct SomeStruct Foo<&'x isize>> { //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context } -enum SomeEnum Foo<&'x isize>> { +enum SomeEnum<'b, I: for<'a> Foo<&'a isize>> { TupleVariant(I::A), //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context StructVariant { field: I::A }, //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context + OkVariant(&'b usize), } // FIXME(eddyb) This one doesn't even compile because of the unsupported syntax. @@ -26,7 +27,13 @@ enum SomeEnum Foo<&'x isize>> { // } struct YetAnotherStruct<'a, I: for<'x> Foo<&'x isize>> { - field: >::A + field: >::A, +} + +struct Why<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x, + 'y, 'z, 'aa, I: for<'l, 'm> Foo<&'l &'m isize>> { + field: I::A, + //~^ ERROR cannot extract an associated type from a higher-ranked trait bound in this context } pub fn main() {} diff --git a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr index c71bc70ea6c..e3fd2860ebc 100644 --- a/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr +++ b/src/test/ui/associated-types/associated-types-project-from-hrtb-in-struct.stderr @@ -18,8 +18,8 @@ LL | TupleVariant(I::A), | help: use a fully qualified path with explicit lifetimes | -LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> { -LL | TupleVariant(>::A), +LL | enum SomeEnum<'c, 'b, I: for<'a> Foo<&'a isize>> { +LL | TupleVariant(>::A), | error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context @@ -30,11 +30,24 @@ LL | StructVariant { field: I::A }, | help: use a fully qualified path with explicit lifetimes | -LL | enum SomeEnum<'a, I: for<'x> Foo<&'x isize>> { +LL | enum SomeEnum<'c, 'b, I: for<'a> Foo<&'a isize>> { LL | TupleVariant(I::A), LL | -LL | StructVariant { field: >::A }, +LL | StructVariant { field: >::A }, | -error: aborting due to 3 previous errors +error[E0212]: cannot extract an associated type from a higher-ranked trait bound in this context + --> $DIR/associated-types-project-from-hrtb-in-struct.rs:35:12 + | +LL | field: I::A, + | ^^^^ + | +help: use a fully qualified path with explicit lifetimes + | +LL | struct Why<'bb, 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'n, 'o, 'p, 'q, 'r, 's, 't, 'u, 'v, 'w, 'x, +LL | 'y, 'z, 'aa, I: for<'l, 'm> Foo<&'l &'m isize>> { +LL | field: >::A, + | + +error: aborting due to 4 previous errors diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-1.rs b/src/test/ui/associated-types/defaults-cyclic-fail-1.rs new file mode 100644 index 00000000000..71ac914ef57 --- /dev/null +++ b/src/test/ui/associated-types/defaults-cyclic-fail-1.rs @@ -0,0 +1,45 @@ +#![feature(associated_type_defaults)] + +// Having a cycle in assoc. type defaults is okay... +trait Tr { + type A = Self::B; + type B = Self::A; +} + +// ...but is an error in any impl that doesn't override at least one of the defaults +impl Tr for () {} +//~^ ERROR overflow evaluating the requirement + +// As soon as at least one is redefined, it works: +impl Tr for u8 { + type A = u8; +} + +impl Tr for u16 { + type B = (); +} + +impl Tr for u32 { + type A = (); + type B = u8; +} + +// ...but only if this actually breaks the cycle +impl Tr for bool { +//~^ ERROR overflow evaluating the requirement + type A = Box; + //~^ ERROR overflow evaluating the requirement +} +// (the error is shown twice for some reason) + +impl Tr for usize { +//~^ ERROR overflow evaluating the requirement + type B = &'static Self::A; + //~^ ERROR overflow evaluating the requirement +} + +fn main() { + // We don't check that the types project correctly because the cycle errors stop compilation + // before `main` is type-checked. + // `defaults-cyclic-pass-1.rs` does this. +} diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr b/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr new file mode 100644 index 00000000000..6a8526f6aad --- /dev/null +++ b/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr @@ -0,0 +1,33 @@ +error[E0275]: overflow evaluating the requirement `<() as Tr>::B` + --> $DIR/defaults-cyclic-fail-1.rs:10:6 + | +LL | impl Tr for () {} + | ^^ + +error[E0275]: overflow evaluating the requirement `::B` + --> $DIR/defaults-cyclic-fail-1.rs:28:6 + | +LL | impl Tr for bool { + | ^^ + +error[E0275]: overflow evaluating the requirement `::B` + --> $DIR/defaults-cyclic-fail-1.rs:35:6 + | +LL | impl Tr for usize { + | ^^ + +error[E0275]: overflow evaluating the requirement `::B` + --> $DIR/defaults-cyclic-fail-1.rs:30:5 + | +LL | type A = Box; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement `::A` + --> $DIR/defaults-cyclic-fail-1.rs:37:5 + | +LL | type B = &'static Self::A; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-2.rs b/src/test/ui/associated-types/defaults-cyclic-fail-2.rs new file mode 100644 index 00000000000..05091e3f498 --- /dev/null +++ b/src/test/ui/associated-types/defaults-cyclic-fail-2.rs @@ -0,0 +1,47 @@ +#![feature(associated_type_defaults)] + +// A more complex version of `defaults-cyclic-fail-1.rs`, with non-trivial defaults. + +// Having a cycle in assoc. type defaults is okay... +trait Tr { + type A = Vec; + type B = Box; +} + +// ...but is an error in any impl that doesn't override at least one of the defaults +impl Tr for () {} +//~^ ERROR overflow evaluating the requirement + +// As soon as at least one is redefined, it works: +impl Tr for u8 { + type A = u8; +} + +impl Tr for u16 { + type B = (); +} + +impl Tr for u32 { + type A = (); + type B = u8; +} + +// ...but only if this actually breaks the cycle +impl Tr for bool { +//~^ ERROR overflow evaluating the requirement + type A = Box; + //~^ ERROR overflow evaluating the requirement +} +// (the error is shown twice for some reason) + +impl Tr for usize { +//~^ ERROR overflow evaluating the requirement + type B = &'static Self::A; + //~^ ERROR overflow evaluating the requirement +} + +fn main() { + // We don't check that the types project correctly because the cycle errors stop compilation + // before `main` is type-checked. + // `defaults-cyclic-pass-2.rs` does this. +} diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr b/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr new file mode 100644 index 00000000000..78772df9638 --- /dev/null +++ b/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr @@ -0,0 +1,33 @@ +error[E0275]: overflow evaluating the requirement `<() as Tr>::B` + --> $DIR/defaults-cyclic-fail-2.rs:12:6 + | +LL | impl Tr for () {} + | ^^ + +error[E0275]: overflow evaluating the requirement `::B` + --> $DIR/defaults-cyclic-fail-2.rs:30:6 + | +LL | impl Tr for bool { + | ^^ + +error[E0275]: overflow evaluating the requirement `::B` + --> $DIR/defaults-cyclic-fail-2.rs:37:6 + | +LL | impl Tr for usize { + | ^^ + +error[E0275]: overflow evaluating the requirement `::B` + --> $DIR/defaults-cyclic-fail-2.rs:32:5 + | +LL | type A = Box; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0275]: overflow evaluating the requirement `::A` + --> $DIR/defaults-cyclic-fail-2.rs:39:5 + | +LL | type B = &'static Self::A; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/defaults-cyclic-pass-1.rs b/src/test/ui/associated-types/defaults-cyclic-pass-1.rs new file mode 100644 index 00000000000..97c6e5bade2 --- /dev/null +++ b/src/test/ui/associated-types/defaults-cyclic-pass-1.rs @@ -0,0 +1,56 @@ +// check-pass + +#![feature(associated_type_defaults)] + +// Having a cycle in assoc. type defaults is okay, as long as there's no impl +// that retains it. +trait Tr { + type A = Self::B; + type B = Self::A; + + fn f(); +} + +// An impl has to break the cycle to be accepted. +impl Tr for u8 { + type A = u8; + + fn f() { + // Check that the type propagates as expected (seen from inside the impl) + let _: Self::A = 0u8; + let _: Self::B = 0u8; + } +} + +impl Tr for String { + type B = (); + + fn f() { + // Check that the type propagates as expected (seen from inside the impl) + let _: Self::A = (); + let _: Self::B = (); + } +} + +impl Tr for () { + type A = Vec<()>; + type B = u8; + + fn f() { + // Check that the type propagates as expected (seen from inside the impl) + let _: Self::A = Vec::<()>::new(); + let _: Self::B = 0u8; + } +} + +fn main() { + // Check that both impls now have the right types (seen from outside the impls) + let _: ::A = 0u8; + let _: ::B = 0u8; + + let _: ::A = (); + let _: ::B = (); + + let _: <() as Tr>::A = Vec::<()>::new(); + let _: <() as Tr>::B = 0u8; +} diff --git a/src/test/ui/associated-types/defaults-cyclic-pass-2.rs b/src/test/ui/associated-types/defaults-cyclic-pass-2.rs new file mode 100644 index 00000000000..69315a02210 --- /dev/null +++ b/src/test/ui/associated-types/defaults-cyclic-pass-2.rs @@ -0,0 +1,56 @@ +// check-pass + +#![feature(associated_type_defaults)] + +// Having a cycle in assoc. type defaults is okay, as long as there's no impl +// that retains it. +trait Tr { + type A = Vec; + type B = Box; + + fn f(); +} + +// An impl has to break the cycle to be accepted. +impl Tr for u8 { + type A = u8; + + fn f() { + // Check that the type propagates as expected (seen from inside the impl) + let _: Self::A = 0u8; + let _: Self::B = Box::new(0u8); + } +} + +impl Tr for String { + type B = (); + + fn f() { + // Check that the type propagates as expected (seen from inside the impl) + let _: Self::A = Vec::<()>::new(); + let _: Self::B = (); + } +} + +impl Tr for () { + type A = Vec<()>; + type B = u8; + + fn f() { + // Check that the type propagates as expected (seen from inside the impl) + let _: Self::A = Vec::<()>::new(); + let _: Self::B = 0u8; + } +} + +fn main() { + // Check that both impls now have the right types (seen from outside the impls) + let _: ::A = 0u8; + let _: ::B = Box::new(0u8); + + let _: ::A = Vec::<()>::new(); + let _: ::B = (); + + let _: <() as Tr>::A = Vec::<()>::new(); + let _: <() as Tr>::B = 0u8; +} diff --git a/src/test/ui/associated-types/defaults-in-other-trait-items-pass.rs b/src/test/ui/associated-types/defaults-in-other-trait-items-pass.rs new file mode 100644 index 00000000000..a3bfcd8efe2 --- /dev/null +++ b/src/test/ui/associated-types/defaults-in-other-trait-items-pass.rs @@ -0,0 +1,37 @@ +// check-pass + +#![feature(associated_type_defaults)] + +trait Tr { + type Item = u8; + type Container = Vec; +} + +impl Tr for () {} + +impl Tr for u16 { + type Item = u16; +} + +impl Tr for String { + type Container = String; +} + +impl Tr for usize { + type Item = u32; + type Container = Vec<()>; +} + +fn main() { + let _container: <() as Tr>::Container = Vec::::new(); + let _item: <() as Tr>::Item = 0u8; + + let _container: ::Container = Vec::::new(); + let _item: ::Item = 0u16; + + let _container: ::Container = String::new(); + let _item: ::Item = 0u8; + + let _container: ::Container = Vec::<()>::new(); + let _item: ::Item = 0u32; +} diff --git a/src/test/ui/associated-types/defaults-in-other-trait-items.rs b/src/test/ui/associated-types/defaults-in-other-trait-items.rs new file mode 100644 index 00000000000..9f2e8aca477 --- /dev/null +++ b/src/test/ui/associated-types/defaults-in-other-trait-items.rs @@ -0,0 +1,50 @@ +#![feature(associated_type_defaults)] + +// Associated type defaults may not be assumed inside the trait defining them. +// ie. they only resolve to `::A`, not the actual type `()` +trait Tr { + type A = (); + + fn f(p: Self::A) { + let () = p; + //~^ ERROR mismatched types + //~| NOTE expected associated type, found `()` + //~| NOTE expected associated type `::A` + //~| NOTE consider constraining the associated type + //~| NOTE for more information, visit + } +} + +// An impl that doesn't override the type *can* assume the default. +impl Tr for () { + fn f(p: Self::A) { + let () = p; + } +} + +impl Tr for u8 { + type A = (); + + fn f(p: Self::A) { + let () = p; + } +} + +trait AssocConst { + type Ty = u8; + + // Assoc. consts also cannot assume that default types hold + const C: Self::Ty = 0u8; + //~^ ERROR mismatched types + //~| NOTE expected associated type, found `u8` + //~| NOTE expected associated type `::Ty` + //~| NOTE consider constraining the associated type + //~| NOTE for more information, visit +} + +// An impl can, however +impl AssocConst for () { + const C: Self::Ty = 0u8; +} + +fn main() {} diff --git a/src/test/ui/associated-types/defaults-in-other-trait-items.stderr b/src/test/ui/associated-types/defaults-in-other-trait-items.stderr new file mode 100644 index 00000000000..9ecfe49c2b5 --- /dev/null +++ b/src/test/ui/associated-types/defaults-in-other-trait-items.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/defaults-in-other-trait-items.rs:9:13 + | +LL | let () = p; + | ^^ expected associated type, found `()` + | + = note: expected associated type `::A` + found unit type `()` + = note: consider constraining the associated type `::A` to `()` or calling a method that returns `::A` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0308]: mismatched types + --> $DIR/defaults-in-other-trait-items.rs:37:25 + | +LL | const C: Self::Ty = 0u8; + | ^^^ expected associated type, found `u8` + | + = note: expected associated type `::Ty` + found type `u8` + = note: consider constraining the associated type `::Ty` to `u8` or calling a method that returns `::Ty` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/associated-types/defaults-mixed.rs b/src/test/ui/associated-types/defaults-mixed.rs new file mode 100644 index 00000000000..c91b8de39f5 --- /dev/null +++ b/src/test/ui/associated-types/defaults-mixed.rs @@ -0,0 +1,34 @@ +#![feature(associated_type_defaults)] + +// Tests that a trait with one defaulted and one non-defaulted assoc. type behaves properly. + +trait Trait { + type Foo = u8; + type Bar; +} + +// `Bar` must be specified +impl Trait for () {} +//~^ error: not all trait items implemented, missing: `Bar` + +impl Trait for bool { +//~^ error: not all trait items implemented, missing: `Bar` + type Foo = (); +} + +impl Trait for u8 { + type Bar = (); +} + +impl Trait for u16 { + type Foo = String; + type Bar = bool; +} + +fn main() { + let _: ::Foo = 0u8; + let _: ::Bar = (); + + let _: ::Foo = String::new(); + let _: ::Bar = true; +} diff --git a/src/test/ui/associated-types/defaults-mixed.stderr b/src/test/ui/associated-types/defaults-mixed.stderr new file mode 100644 index 00000000000..69ddd5f2326 --- /dev/null +++ b/src/test/ui/associated-types/defaults-mixed.stderr @@ -0,0 +1,21 @@ +error[E0046]: not all trait items implemented, missing: `Bar` + --> $DIR/defaults-mixed.rs:11:1 + | +LL | type Bar; + | --------- `Bar` from trait +... +LL | impl Trait for () {} + | ^^^^^^^^^^^^^^^^^ missing `Bar` in implementation + +error[E0046]: not all trait items implemented, missing: `Bar` + --> $DIR/defaults-mixed.rs:14:1 + | +LL | type Bar; + | --------- `Bar` from trait +... +LL | impl Trait for bool { + | ^^^^^^^^^^^^^^^^^^^ missing `Bar` in implementation + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0046`. diff --git a/src/test/ui/associated-types/defaults-specialization.rs b/src/test/ui/associated-types/defaults-specialization.rs new file mode 100644 index 00000000000..d0ed718b839 --- /dev/null +++ b/src/test/ui/associated-types/defaults-specialization.rs @@ -0,0 +1,95 @@ +//! Tests the interaction of associated type defaults and specialization. + +#![feature(associated_type_defaults, specialization)] + +trait Tr { + type Ty = u8; + + fn make() -> Self::Ty { + 0u8 + //~^ error: mismatched types + } +} + +struct A(T); +// In a `default impl`, assoc. types are defaulted as well, +// so their values can't be assumed. +default impl Tr for A { + fn make() -> u8 { 0 } + //~^ ERROR method `make` has an incompatible type for trait +} + +struct A2(T); +// ...same, but in the method body +default impl Tr for A2 { + fn make() -> Self::Ty { 0u8 } + //~^ ERROR mismatched types +} + +struct B(T); +// Explicitly defaulting the type does the same. +impl Tr for B { + default type Ty = bool; + + fn make() -> bool { true } + //~^ ERROR method `make` has an incompatible type for trait +} + +struct B2(T); +// ...same, but in the method body +impl Tr for B2 { + default type Ty = bool; + + fn make() -> Self::Ty { true } + //~^ ERROR mismatched types +} + +struct C(T); +// Only the method is defaulted, so this is fine. +impl Tr for C { + type Ty = bool; + + default fn make() -> bool { true } +} + +// Defaulted method *can* assume the type, if the default is kept. +struct D(T); +impl Tr for D { + default fn make() -> u8 { 0 } +} + +impl Tr for D { + fn make() -> u8 { 255 } +} + +struct E(T); +impl Tr for E { + default type Ty = bool; + default fn make() -> Self::Ty { panic!(); } +} + +// This impl specializes and sets `Ty`, it can rely on `Ty=String`. +impl Tr for E { + type Ty = String; + + fn make() -> String { String::new() } +} + +fn main() { + // Test that we can assume the right set of assoc. types from outside the impl + + // This is a `default impl`, which does *not* mean that `A`/`A2` actually implement the trait. + // cf. https://github.com/rust-lang/rust/issues/48515 + //let _: as Tr>::Ty = 0u8; + //let _: as Tr>::Ty = 0u8; + + let _: as Tr>::Ty = 0u8; //~ error: mismatched types + let _: as Tr>::Ty = true; //~ error: mismatched types + let _: as Tr>::Ty = 0u8; //~ error: mismatched types + let _: as Tr>::Ty = true; //~ error: mismatched types + + let _: as Tr>::Ty = true; + + let _: as Tr>::Ty = 0u8; + let _: as Tr>::Ty = 0u8; +} diff --git a/src/test/ui/associated-types/defaults-specialization.stderr b/src/test/ui/associated-types/defaults-specialization.stderr new file mode 100644 index 00000000000..1dd536ec636 --- /dev/null +++ b/src/test/ui/associated-types/defaults-specialization.stderr @@ -0,0 +1,123 @@ +error[E0053]: method `make` has an incompatible type for trait + --> $DIR/defaults-specialization.rs:18:18 + | +LL | fn make() -> Self::Ty { + | -------- type in trait +... +LL | fn make() -> u8 { 0 } + | ^^ expected associated type, found `u8` + | + = note: expected fn pointer `fn() -> as Tr>::Ty` + found fn pointer `fn() -> u8` + = note: consider constraining the associated type ` as Tr>::Ty` to `u8` or calling a method that returns ` as Tr>::Ty` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0053]: method `make` has an incompatible type for trait + --> $DIR/defaults-specialization.rs:34:18 + | +LL | fn make() -> Self::Ty { + | -------- type in trait +... +LL | fn make() -> bool { true } + | ^^^^ expected associated type, found `bool` + | + = note: expected fn pointer `fn() -> as Tr>::Ty` + found fn pointer `fn() -> bool` + = note: consider constraining the associated type ` as Tr>::Ty` to `bool` or calling a method that returns ` as Tr>::Ty` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0308]: mismatched types + --> $DIR/defaults-specialization.rs:9:9 + | +LL | fn make() -> Self::Ty { + | -------- expected `::Ty` because of return type +LL | 0u8 + | ^^^ expected associated type, found `u8` + | + = note: expected associated type `::Ty` + found type `u8` + = note: consider constraining the associated type `::Ty` to `u8` or calling a method that returns `::Ty` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0308]: mismatched types + --> $DIR/defaults-specialization.rs:25:29 + | +LL | fn make() -> Self::Ty { 0u8 } + | -------- ^^^ expected associated type, found `u8` + | | + | expected ` as Tr>::Ty` because of return type + | + = note: expected associated type ` as Tr>::Ty` + found type `u8` + = note: consider constraining the associated type ` as Tr>::Ty` to `u8` or calling a method that returns ` as Tr>::Ty` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0308]: mismatched types + --> $DIR/defaults-specialization.rs:43:29 + | +LL | fn make() -> Self::Ty { true } + | -------- ^^^^ expected associated type, found `bool` + | | + | expected ` as Tr>::Ty` because of return type + | + = note: expected associated type ` as Tr>::Ty` + found type `bool` + = note: consider constraining the associated type ` as Tr>::Ty` to `bool` or calling a method that returns ` as Tr>::Ty` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0308]: mismatched types + --> $DIR/defaults-specialization.rs:86:32 + | +LL | let _: as Tr>::Ty = 0u8; + | ----------------- ^^^ expected associated type, found `u8` + | | + | expected due to this + | + = note: expected associated type ` as Tr>::Ty` + found type `u8` + = note: consider constraining the associated type ` as Tr>::Ty` to `u8` or calling a method that returns ` as Tr>::Ty` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0308]: mismatched types + --> $DIR/defaults-specialization.rs:87:32 + | +LL | let _: as Tr>::Ty = true; + | ----------------- ^^^^ expected associated type, found `bool` + | | + | expected due to this + | + = note: expected associated type ` as Tr>::Ty` + found type `bool` + = note: consider constraining the associated type ` as Tr>::Ty` to `bool` or calling a method that returns ` as Tr>::Ty` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0308]: mismatched types + --> $DIR/defaults-specialization.rs:88:33 + | +LL | let _: as Tr>::Ty = 0u8; + | ------------------ ^^^ expected associated type, found `u8` + | | + | expected due to this + | + = note: expected associated type ` as Tr>::Ty` + found type `u8` + = note: consider constraining the associated type ` as Tr>::Ty` to `u8` or calling a method that returns ` as Tr>::Ty` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error[E0308]: mismatched types + --> $DIR/defaults-specialization.rs:89:33 + | +LL | let _: as Tr>::Ty = true; + | ------------------ ^^^^ expected associated type, found `bool` + | | + | expected due to this + | + = note: expected associated type ` as Tr>::Ty` + found type `bool` + = note: consider constraining the associated type ` as Tr>::Ty` to `bool` or calling a method that returns ` as Tr>::Ty` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0053, E0308. +For more information about an error, try `rustc --explain E0053`. diff --git a/src/test/ui/associated-types/defaults-suitability.rs b/src/test/ui/associated-types/defaults-suitability.rs new file mode 100644 index 00000000000..2be01cba105 --- /dev/null +++ b/src/test/ui/associated-types/defaults-suitability.rs @@ -0,0 +1,106 @@ +//! Checks that associated type defaults are properly validated. +//! +//! This means: +//! * Default types are wfchecked +//! * Default types are checked against where clauses on the assoc. type +//! (eg. `type Assoc: Clone = NotClone`), and also against where clauses on +//! the trait itself when possible + +#![feature(associated_type_defaults)] + +struct NotClone; + +// Assoc. type bounds must hold for the default type +trait Tr { + type Ty: Clone = NotClone; + //~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied +} + +// Where-clauses defined on the trait must also be considered +trait Tr2 where Self::Ty: Clone { + //~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied + type Ty = NotClone; +} + +// Independent of where-clauses (there are none here), default types must always be wf +trait Tr3 { + type Ty = Vec<[u8]>; + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time +} + +// Involved type parameters must fulfill all bounds required by defaults that mention them +trait Foo { + type Bar: Clone = Vec; + //~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied +} + +trait Bar: Sized { + // `(): Foo` might hold for some possible impls but not all. + type Assoc: Foo = (); + //~^ ERROR the trait bound `(): Foo` is not satisfied +} + +trait IsU8 {} +impl IsU8 for T {} + +// Test that mentioning the assoc. type inside where clauses works +trait C where + Vec: Clone, + Self::Assoc: IsU8, + bool: IsU8, +{ + type Assoc = u8; +} + +// Test that we get all expected errors if that default is unsuitable +trait D where + Vec: Clone, + //~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied + Self::Assoc: IsU8, + //~^ ERROR the trait bound `NotClone: IsU8` is not satisfied + bool: IsU8, + //~^ ERROR the trait bound `bool: IsU8` is not satisfied +{ + type Assoc = NotClone; +} + +// Test behavior of the check when defaults refer to other defaults: + +// Shallow substitution rejects this trait since `Baz` isn't guaranteed to be +// `Clone`. +trait Foo2 { + type Bar: Clone = Vec; + //~^ ERROR the trait bound `>::Baz: std::clone::Clone` is not satisfied + type Baz = T; +} + +// Adding a `T: Clone` bound doesn't help since the requirement doesn't see `T` +// because of the shallow substitution. If we did a deep substitution instead, +// this would be accepted. +trait Foo25 { + type Bar: Clone = Vec; + //~^ ERROR the trait bound `>::Baz: std::clone::Clone` is not satisfied + type Baz = T; +} + +// Adding the `Baz: Clone` bound isn't enough since the default is type +// parameter `T`, which also might not be `Clone`. +trait Foo3 where + Self::Bar: Clone, + Self::Baz: Clone, + //~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied +{ + type Bar = Vec; + type Baz = T; +} + +// This one finally works, with `Clone` bounds on all assoc. types and the type +// parameter. +trait Foo4 where + T: Clone, +{ + type Bar: Clone = Vec; + type Baz: Clone = T; +} + +fn main() {} diff --git a/src/test/ui/associated-types/defaults-suitability.stderr b/src/test/ui/associated-types/defaults-suitability.stderr new file mode 100644 index 00000000000..60e1821b300 --- /dev/null +++ b/src/test/ui/associated-types/defaults-suitability.stderr @@ -0,0 +1,140 @@ +error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied + --> $DIR/defaults-suitability.rs:15:14 + | +LL | trait Tr { + | -------- required by `Tr` +LL | type Ty: Clone = NotClone; + | ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone` + +error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied + --> $DIR/defaults-suitability.rs:20:27 + | +LL | trait Tr2 where Self::Ty: Clone { + | --------------------------^^^^^ + | | | + | | the trait `std::clone::Clone` is not implemented for `NotClone` + | required by `Tr2` + +error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied + --> $DIR/defaults-suitability.rs:33:15 + | +LL | trait Foo { + | ------------ required by `Foo` +LL | type Bar: Clone = Vec; + | ^^^^^ the trait `std::clone::Clone` is not implemented for `T` + | +help: consider restricting this type parameter with `T: std::clone::Clone` + --> $DIR/defaults-suitability.rs:32:11 + | +LL | trait Foo { + | ^ + = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec` + +error[E0277]: the trait bound `(): Foo` is not satisfied + --> $DIR/defaults-suitability.rs:39:17 + | +LL | trait Bar: Sized { + | ---------------- required by `Bar` +LL | // `(): Foo` might hold for some possible impls but not all. +LL | type Assoc: Foo = (); + | ^^^^^^^^^ the trait `Foo` is not implemented for `()` + +error[E0277]: the trait bound `NotClone: IsU8` is not satisfied + --> $DIR/defaults-suitability.rs:59:18 + | +LL | / trait D where +LL | | Vec: Clone, +LL | | +LL | | Self::Assoc: IsU8, + | | ^^^^^^^^^^^^^^^^^ the trait `IsU8` is not implemented for `NotClone` +... | +LL | | type Assoc = NotClone; +LL | | } + | |_- required by `D` + +error[E0277]: the trait bound `bool: IsU8` is not satisfied + --> $DIR/defaults-suitability.rs:61:11 + | +LL | / trait D where +LL | | Vec: Clone, +LL | | +LL | | Self::Assoc: IsU8, +LL | | +LL | | bool: IsU8, + | | ^^^^^^^^^^^^^^^^^ the trait `IsU8` is not implemented for `bool` +... | +LL | | type Assoc = NotClone; +LL | | } + | |_- required by `D` + +error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied + --> $DIR/defaults-suitability.rs:57:23 + | +LL | / trait D where +LL | | Vec: Clone, + | | ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone` +LL | | +LL | | Self::Assoc: IsU8, +... | +LL | | type Assoc = NotClone; +LL | | } + | |_- required by `D` + | + = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec` + +error[E0277]: the trait bound `>::Baz: std::clone::Clone` is not satisfied + --> $DIR/defaults-suitability.rs:72:15 + | +LL | trait Foo2 { + | -------------- help: consider further restricting the associated type: `where >::Baz: std::clone::Clone` + | | + | required by `Foo2` +LL | type Bar: Clone = Vec; + | ^^^^^ the trait `std::clone::Clone` is not implemented for `>::Baz` + | + = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<>::Baz>` + +error[E0277]: the trait bound `>::Baz: std::clone::Clone` is not satisfied + --> $DIR/defaults-suitability.rs:81:15 + | +LL | trait Foo25 { + | ---------------------- help: consider further restricting the associated type: `where >::Baz: std::clone::Clone` + | | + | required by `Foo25` +LL | type Bar: Clone = Vec; + | ^^^^^ the trait `std::clone::Clone` is not implemented for `>::Baz` + | + = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<>::Baz>` + +error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied + --> $DIR/defaults-suitability.rs:90:16 + | +LL | / trait Foo3 where +LL | | Self::Bar: Clone, +LL | | Self::Baz: Clone, + | | ^^^^^ the trait `std::clone::Clone` is not implemented for `T` +LL | | +... | +LL | | type Baz = T; +LL | | } + | |_- required by `Foo3` + | +help: consider restricting this type parameter with `where T: std::clone::Clone` + --> $DIR/defaults-suitability.rs:88:12 + | +LL | trait Foo3 where + | ^ + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/defaults-suitability.rs:27:5 + | +LL | type Ty = Vec<[u8]>; + | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = note: to learn more, visit + = note: required by `std::vec::Vec` + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.rs b/src/test/ui/associated-types/defaults-unsound-62211-1.rs new file mode 100644 index 00000000000..c8b4734d6ed --- /dev/null +++ b/src/test/ui/associated-types/defaults-unsound-62211-1.rs @@ -0,0 +1,63 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/62211 +//! +//! The old implementation of defaults did not check whether the provided +//! default actually fulfills all bounds on the assoc. type, leading to +//! unsoundness, demonstrated here as a use-after-free. +//! +//! Note that the underlying cause of this is still not yet fixed. +//! See: https://github.com/rust-lang/rust/issues/33017 + +#![feature(associated_type_defaults)] + +use std::{ + fmt::Display, + ops::{AddAssign, Deref} +}; + + +trait UncheckedCopy: Sized { + // This Output is said to be Copy. Yet we default to Self + // and it's accepted, not knowing if Self ineed is Copy + type Output: Copy + //~^ ERROR the trait bound `Self: std::marker::Copy` is not satisfied + + Deref + //~^ ERROR the trait bound `Self: std::ops::Deref` is not satisfied + + AddAssign<&'static str> + //~^ ERROR cannot add-assign `&'static str` to `Self` + + From + + Display = Self; + //~^ ERROR `Self` doesn't implement `std::fmt::Display` + + // We said the Output type was Copy, so we can Copy it freely! + fn unchecked_copy(other: &Self::Output) -> Self::Output { + (*other) + } + + fn make_origin(s: Self) -> Self::Output { + s.into() + } +} + +impl UncheckedCopy for T {} +//~^ ERROR `T` doesn't implement `std::fmt::Display` +//~| ERROR the trait bound `T: std::ops::Deref` is not satisfied +//~| ERROR cannot add-assign `&'static str` to `T` +//~| ERROR the trait bound `T: std::marker::Copy` is not satisfied + +fn bug(origin: T) { + let origin = T::make_origin(origin); + let mut copy = T::unchecked_copy(&origin); + + // assert we indeed have 2 strings pointing to the same buffer. + assert_eq!(origin.as_ptr(), copy.as_ptr()); + + // Drop the origin. Any use of `copy` is UB. + drop(origin); + + copy += "This is invalid!"; + println!("{}", copy); +} + +fn main() { + bug(String::from("hello!")); +} diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr new file mode 100644 index 00000000000..9c4a1260139 --- /dev/null +++ b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr @@ -0,0 +1,95 @@ +error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied + --> $DIR/defaults-unsound-62211-1.rs:21:18 + | +LL | trait UncheckedCopy: Sized { + | -------------------------- required by `UncheckedCopy` +... +LL | type Output: Copy + | ^^^^ the trait `std::marker::Copy` is not implemented for `Self` + +error[E0277]: cannot add-assign `&'static str` to `Self` + --> $DIR/defaults-unsound-62211-1.rs:25:7 + | +LL | trait UncheckedCopy: Sized { + | -------------------------- required by `UncheckedCopy` +... +LL | + AddAssign<&'static str> + | ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str` + | + = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self` + +error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied + --> $DIR/defaults-unsound-62211-1.rs:23:7 + | +LL | trait UncheckedCopy: Sized { + | -------------------------- required by `UncheckedCopy` +... +LL | + Deref + | ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self` + +error[E0277]: `Self` doesn't implement `std::fmt::Display` + --> $DIR/defaults-unsound-62211-1.rs:28:7 + | +LL | trait UncheckedCopy: Sized { + | -------------------------- required by `UncheckedCopy` +... +LL | + Display = Self; + | ^^^^^^^ `Self` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Self` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + +error[E0277]: `T` doesn't implement `std::fmt::Display` + --> $DIR/defaults-unsound-62211-1.rs:41:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `T` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +help: consider restricting this type parameter with `T: std::fmt::Display` + --> $DIR/defaults-unsound-62211-1.rs:41:6 + | +LL | impl UncheckedCopy for T {} + | ^ + +error[E0277]: the trait bound `T: std::ops::Deref` is not satisfied + --> $DIR/defaults-unsound-62211-1.rs:41:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `T` + | +help: consider restricting this type parameter with `T: std::ops::Deref` + --> $DIR/defaults-unsound-62211-1.rs:41:6 + | +LL | impl UncheckedCopy for T {} + | ^ + +error[E0277]: cannot add-assign `&'static str` to `T` + --> $DIR/defaults-unsound-62211-1.rs:41:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ no implementation for `T += &'static str` + | + = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T` +help: consider restricting this type parameter with `T: std::ops::AddAssign<&'static str>` + --> $DIR/defaults-unsound-62211-1.rs:41:6 + | +LL | impl UncheckedCopy for T {} + | ^ + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/defaults-unsound-62211-1.rs:41:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | +help: consider restricting this type parameter with `T: std::marker::Copy` + --> $DIR/defaults-unsound-62211-1.rs:41:6 + | +LL | impl UncheckedCopy for T {} + | ^ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.rs b/src/test/ui/associated-types/defaults-unsound-62211-2.rs new file mode 100644 index 00000000000..aa343e759a8 --- /dev/null +++ b/src/test/ui/associated-types/defaults-unsound-62211-2.rs @@ -0,0 +1,63 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/62211 +//! +//! The old implementation of defaults did not check whether the provided +//! default actually fulfills all bounds on the assoc. type, leading to +//! unsoundness and ICEs, the latter being demonstrated here. +//! +//! Note that the underlying cause of this is still not yet fixed. +//! See: https://github.com/rust-lang/rust/issues/33017 + +#![feature(associated_type_defaults)] + +use std::{ + fmt::Display, + ops::{AddAssign, Deref} +}; + + +trait UncheckedCopy: Sized { + // This Output is said to be Copy. Yet we default to Self + // and it's accepted, not knowing if Self ineed is Copy + type Output: Copy + //~^ ERROR the trait bound `Self: std::marker::Copy` is not satisfied + + Deref + //~^ ERROR the trait bound `Self: std::ops::Deref` is not satisfied + + AddAssign<&'static str> + //~^ ERROR cannot add-assign `&'static str` to `Self` + + From + + Display = Self; + //~^ ERROR `Self` doesn't implement `std::fmt::Display` + + // We said the Output type was Copy, so we can Copy it freely! + fn unchecked_copy(other: &Self::Output) -> Self::Output { + (*other) + } + + fn make_origin(s: Self) -> Self::Output { + s.into() + } +} + +impl UncheckedCopy for T {} +//~^ ERROR `T` doesn't implement `std::fmt::Display` +//~| ERROR the trait bound `T: std::ops::Deref` is not satisfied +//~| ERROR cannot add-assign `&'static str` to `T` +//~| ERROR the trait bound `T: std::marker::Copy` is not satisfied + +fn bug(origin: T) { + let origin = T::make_origin(origin); + let mut copy = T::unchecked_copy(&origin); + + // assert we indeed have 2 strings pointing to the same buffer. + assert_eq!(origin.as_ptr(), copy.as_ptr()); + + // Drop the origin. Any use of `copy` is UB. + drop(origin); + + copy += "This is invalid!"; + println!("{}", copy); +} + +fn main() { + bug(()); +} diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr new file mode 100644 index 00000000000..4602fbc99fa --- /dev/null +++ b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr @@ -0,0 +1,95 @@ +error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied + --> $DIR/defaults-unsound-62211-2.rs:21:18 + | +LL | trait UncheckedCopy: Sized { + | -------------------------- required by `UncheckedCopy` +... +LL | type Output: Copy + | ^^^^ the trait `std::marker::Copy` is not implemented for `Self` + +error[E0277]: cannot add-assign `&'static str` to `Self` + --> $DIR/defaults-unsound-62211-2.rs:25:7 + | +LL | trait UncheckedCopy: Sized { + | -------------------------- required by `UncheckedCopy` +... +LL | + AddAssign<&'static str> + | ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str` + | + = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self` + +error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied + --> $DIR/defaults-unsound-62211-2.rs:23:7 + | +LL | trait UncheckedCopy: Sized { + | -------------------------- required by `UncheckedCopy` +... +LL | + Deref + | ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self` + +error[E0277]: `Self` doesn't implement `std::fmt::Display` + --> $DIR/defaults-unsound-62211-2.rs:28:7 + | +LL | trait UncheckedCopy: Sized { + | -------------------------- required by `UncheckedCopy` +... +LL | + Display = Self; + | ^^^^^^^ `Self` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Self` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + +error[E0277]: `T` doesn't implement `std::fmt::Display` + --> $DIR/defaults-unsound-62211-2.rs:41:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `T` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +help: consider restricting this type parameter with `T: std::fmt::Display` + --> $DIR/defaults-unsound-62211-2.rs:41:6 + | +LL | impl UncheckedCopy for T {} + | ^ + +error[E0277]: the trait bound `T: std::ops::Deref` is not satisfied + --> $DIR/defaults-unsound-62211-2.rs:41:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `T` + | +help: consider restricting this type parameter with `T: std::ops::Deref` + --> $DIR/defaults-unsound-62211-2.rs:41:6 + | +LL | impl UncheckedCopy for T {} + | ^ + +error[E0277]: cannot add-assign `&'static str` to `T` + --> $DIR/defaults-unsound-62211-2.rs:41:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ no implementation for `T += &'static str` + | + = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T` +help: consider restricting this type parameter with `T: std::ops::AddAssign<&'static str>` + --> $DIR/defaults-unsound-62211-2.rs:41:6 + | +LL | impl UncheckedCopy for T {} + | ^ + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/defaults-unsound-62211-2.rs:41:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | +help: consider restricting this type parameter with `T: std::marker::Copy` + --> $DIR/defaults-unsound-62211-2.rs:41:6 + | +LL | impl UncheckedCopy for T {} + | ^ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/issue-26681.rs b/src/test/ui/associated-types/issue-26681.rs new file mode 100644 index 00000000000..a0a8c86d949 --- /dev/null +++ b/src/test/ui/associated-types/issue-26681.rs @@ -0,0 +1,20 @@ +#![feature(associated_type_defaults)] + +// This is a partial regression test for #26681, which used to fail to resolve +// `Self` in the assoc. constant, and now fails with a type mismatch because +// `Self::Fv` cannot be assumed to equal `u8` inside the trait. + +trait Foo { + type Bar; +} + +impl Foo for u8 { + type Bar = (); +} + +trait Baz { + type Fv: Foo = u8; + const C: ::Bar = 6665; //~ error: mismatched types +} + +fn main() {} diff --git a/src/test/ui/associated-types/issue-26681.stderr b/src/test/ui/associated-types/issue-26681.stderr new file mode 100644 index 00000000000..da10933df92 --- /dev/null +++ b/src/test/ui/associated-types/issue-26681.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-26681.rs:17:39 + | +LL | const C: ::Bar = 6665; + | ^^^^ expected associated type, found integer + | + = note: expected associated type `<::Fv as Foo>::Bar` + found type `{integer}` + = note: consider constraining the associated type `<::Fv as Foo>::Bar` to `{integer}` or calling a method that returns `<::Fv as Foo>::Bar` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/associated-types/issue-32350.rs b/src/test/ui/associated-types/issue-32350.rs new file mode 100644 index 00000000000..bda21eb0e0a --- /dev/null +++ b/src/test/ui/associated-types/issue-32350.rs @@ -0,0 +1,29 @@ +// check-pass + +// This is another instance of the "normalizations don't work" issue with +// defaulted associated types. + +#![feature(associated_type_defaults)] + +pub trait Emitter<'a> { + type Ctxt: 'a; + type CtxtBrw: 'a = &'a Self::Ctxt; + + fn get_cx(&'a self) -> Self::CtxtBrw; +} + +struct MyCtxt; + +struct MyEmitter { + ctxt: MyCtxt +} + +impl <'a> Emitter<'a> for MyEmitter { + type Ctxt = MyCtxt; + + fn get_cx(&'a self) -> &'a MyCtxt { + &self.ctxt + } +} + +fn main() {} diff --git a/src/test/ui/associated-types/issue-41868.rs b/src/test/ui/associated-types/issue-41868.rs new file mode 100644 index 00000000000..52bbd1f5d28 --- /dev/null +++ b/src/test/ui/associated-types/issue-41868.rs @@ -0,0 +1,23 @@ +// check-pass + +// Defaulted assoc. types should normalize properly in impls that don't +// override them. + +#![feature(associated_type_defaults)] + +pub struct Foo; + +pub trait CanDecode: Sized { + type Output = Self; + fn read(rdr: &mut Foo) -> Option; +} + +impl CanDecode for u8 { + fn read(rdr: &mut Foo) -> Option { Some(42) } +} + +impl CanDecode for u16 { + fn read(rdr: &mut Foo) -> Option { Some(17) } +} + +fn main() {} diff --git a/src/test/ui/associated-types/issue-43924.rs b/src/test/ui/associated-types/issue-43924.rs new file mode 100644 index 00000000000..26f1183c6bd --- /dev/null +++ b/src/test/ui/associated-types/issue-43924.rs @@ -0,0 +1,15 @@ +#![feature(associated_type_defaults)] + +// This used to cause an ICE because assoc. type defaults weren't properly +// type-checked. + +trait Foo { + type Out: Default + ToString + ?Sized = dyn ToString; //~ error: not satisfied +} + +impl Foo for () {} //~ error: not satisfied +impl Foo for () {} //~ error: not satisfied + +fn main() { + assert_eq!(<() as Foo>::Out::default().to_string(), "false"); +} diff --git a/src/test/ui/associated-types/issue-43924.stderr b/src/test/ui/associated-types/issue-43924.stderr new file mode 100644 index 00000000000..75a5b3f3551 --- /dev/null +++ b/src/test/ui/associated-types/issue-43924.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `(dyn std::string::ToString + 'static): std::default::Default` is not satisfied + --> $DIR/issue-43924.rs:7:15 + | +LL | trait Foo { + | -------------------------------- required by `Foo` +LL | type Out: Default + ToString + ?Sized = dyn ToString; + | ^^^^^^^ the trait `std::default::Default` is not implemented for `(dyn std::string::ToString + 'static)` + +error[E0277]: the trait bound `(dyn std::string::ToString + 'static): std::default::Default` is not satisfied + --> $DIR/issue-43924.rs:10:6 + | +LL | impl Foo for () {} + | ^^^^^^^^ the trait `std::default::Default` is not implemented for `(dyn std::string::ToString + 'static)` + +error[E0277]: the trait bound `(dyn std::string::ToString + 'static): std::default::Default` is not satisfied + --> $DIR/issue-43924.rs:11:6 + | +LL | impl Foo for () {} + | ^^^^^^^^ the trait `std::default::Default` is not implemented for `(dyn std::string::ToString + 'static)` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/issue-47385.rs b/src/test/ui/associated-types/issue-47385.rs new file mode 100644 index 00000000000..d43d674e9c3 --- /dev/null +++ b/src/test/ui/associated-types/issue-47385.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(associated_type_defaults)] + +pub struct Foo; + +pub trait Bar: From<::Input> { + type Input = Self; +} + +impl Bar for Foo { + // Will compile with explicit type: + // type Input = Self; +} + +fn main() {} diff --git a/src/test/ui/associated-types/issue-54182-1.rs b/src/test/ui/associated-types/issue-54182-1.rs new file mode 100644 index 00000000000..1a1e98cbac2 --- /dev/null +++ b/src/test/ui/associated-types/issue-54182-1.rs @@ -0,0 +1,92 @@ +// run-pass + +// Tests that the return type of trait methods is correctly normalized when +// checking that a method in an impl matches the trait definition when the +// return type involves a defaulted associated type. +// ie. the trait has a method with return type `-> Self::R`, and `type R = ()`, +// but the impl leaves out the return type (resulting in `()`). +// Note that specialization is not involved in this test; no items in +// implementations may be overridden. If they were, the normalization wouldn't +// happen. + +#![feature(associated_type_defaults)] + +macro_rules! overload { + ($a:expr, $b:expr) => { + overload::overload2($a, $b) + }; + ($a:expr, $b:expr, $c:expr) => { + overload::overload3($a, $b, $c) + } +} + +fn main() { + let () = overload!(42, true); + + let r: f32 = overload!("Hello world", 13.0); + assert_eq!(r, 13.0); + + let () = overload!(42, true, 42.5); + + let r: i32 = overload!("Hello world", 13.0, 42); + assert_eq!(r, 42); +} + +mod overload { + /// This trait has an assoc. type defaulting to `()`, and a required method returning a value + /// of that assoc. type. + pub trait Overload { + // type R; + type R = (); + fn overload(self) -> Self::R; + } + + // overloads for 2 args + impl Overload for (i32, bool) { + // type R = (); + + /// This function has no return type specified, and so defaults to `()`. + /// + /// This should work, but didn't, until RFC 2532 was implemented. + fn overload(self) /*-> Self::R*/ { + let (a, b) = self; // destructure args + println!("i32 and bool {:?}", (a, b)); + } + } + impl<'a> Overload for (&'a str, f32) { + type R = f32; + fn overload(self) -> Self::R { + let (a, b) = self; // destructure args + println!("&str and f32 {:?}", (a, b)); + b + } + } + + // overloads for 3 args + impl Overload for (i32, bool, f32) { + // type R = (); + fn overload(self) /*-> Self::R*/ { + let (a, b, c) = self; // destructure args + println!("i32 and bool and f32 {:?}", (a, b, c)); + } + } + impl<'a> Overload for (&'a str, f32, i32) { + type R = i32; + fn overload(self) -> Self::R { + let (a, b, c) = self; // destructure args + println!("&str and f32 and i32: {:?}", (a, b, c)); + c + } + } + + // overloads for more args + // ... + + pub fn overload2(a: A, b: B) -> R where (A, B): Overload { + (a, b).overload() + } + + pub fn overload3(a: A, b: B, c: C) -> R where (A, B, C): Overload { + (a, b, c).overload() + } +} diff --git a/src/test/ui/associated-types/issue-54182-2.rs b/src/test/ui/associated-types/issue-54182-2.rs new file mode 100644 index 00000000000..c88c7663136 --- /dev/null +++ b/src/test/ui/associated-types/issue-54182-2.rs @@ -0,0 +1,19 @@ +// check-pass + +// Before RFC 2532, normalizing a defaulted assoc. type didn't work at all, +// unless the impl in question overrides that type, which makes the default +// pointless. + +#![feature(associated_type_defaults)] + +trait Tr { + type Assoc = (); +} + +impl Tr for () {} + +fn f(thing: <() as Tr>::Assoc) { + let c: () = thing; +} + +fn main() {} diff --git a/src/test/ui/associated-types/issue-63593.rs b/src/test/ui/associated-types/issue-63593.rs new file mode 100644 index 00000000000..8dbc24c0673 --- /dev/null +++ b/src/test/ui/associated-types/issue-63593.rs @@ -0,0 +1,13 @@ +#![feature(associated_type_defaults)] + +// Tests that `Self` is not assumed to implement `Sized` when used as an +// associated type default. + +trait Inner {} + +trait MyTrait { + type This = Self; //~ error: size for values of type `Self` cannot be known + fn something>(i: I); +} + +fn main() {} diff --git a/src/test/ui/associated-types/issue-63593.stderr b/src/test/ui/associated-types/issue-63593.stderr new file mode 100644 index 00000000000..c27800f5a3f --- /dev/null +++ b/src/test/ui/associated-types/issue-63593.stderr @@ -0,0 +1,14 @@ +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/issue-63593.rs:9:5 + | +LL | trait MyTrait { + | ------------- required by `MyTrait` +LL | type This = Self; + | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `Self` + = note: to learn more, visit + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/issue-65774-1.rs b/src/test/ui/associated-types/issue-65774-1.rs new file mode 100644 index 00000000000..0ffd6cc2cf2 --- /dev/null +++ b/src/test/ui/associated-types/issue-65774-1.rs @@ -0,0 +1,58 @@ +#![feature(associated_type_defaults)] + +trait MyDisplay { fn method(&self) { } } + +impl<'a, T: MyDisplay> MyDisplay for &'a mut T { } + +struct T; + +trait MPU { + type MpuConfig: MyDisplay = T; + //~^ ERROR the trait bound `T: MyDisplay` is not satisfied +} + +struct S; + +impl MPU for S { } +//~^ ERROR the trait bound `T: MyDisplay` is not satisfied + +trait MyWrite { + fn my_write(&self, _: &dyn MyDisplay) { } +} + +trait ProcessType { + fn process_detail_fmt(&self, _: &mut dyn MyWrite); +} + +struct Process; + +impl ProcessType for Process { + fn process_detail_fmt(&self, writer: &mut dyn MyWrite) + { + + let mut val: Option<::MpuConfig> = None; + let valref: &mut ::MpuConfig = val.as_mut().unwrap(); + + // // This causes a different ICE (but its similar if you squint right): + // // + // // `Unimplemented` selecting `Binder()` during codegen + // + // writer.my_write(valref) + + // This one causes the ICE: + // FulfillmentError(Obligation(predicate=Binder(TraitPredicate()), + // depth=1),Unimplemented) + let closure = |config: &mut ::MpuConfig| writer.my_write(&config); + closure(valref); + } +} + +fn create() -> &'static dyn ProcessType { + let input: Option<&mut Process> = None; + let process: &mut Process = input.unwrap(); + process +} + +pub fn main() { + create(); +} diff --git a/src/test/ui/associated-types/issue-65774-1.stderr b/src/test/ui/associated-types/issue-65774-1.stderr new file mode 100644 index 00000000000..559136be705 --- /dev/null +++ b/src/test/ui/associated-types/issue-65774-1.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `T: MyDisplay` is not satisfied + --> $DIR/issue-65774-1.rs:10:21 + | +LL | trait MPU { + | --------- required by `MPU` +LL | type MpuConfig: MyDisplay = T; + | ^^^^^^^^^ the trait `MyDisplay` is not implemented for `T` + +error[E0277]: the trait bound `T: MyDisplay` is not satisfied + --> $DIR/issue-65774-1.rs:16:6 + | +LL | impl MPU for S { } + | ^^^ the trait `MyDisplay` is not implemented for `T` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/issue-65774-2.rs b/src/test/ui/associated-types/issue-65774-2.rs new file mode 100644 index 00000000000..31e203a81d3 --- /dev/null +++ b/src/test/ui/associated-types/issue-65774-2.rs @@ -0,0 +1,58 @@ +#![feature(associated_type_defaults)] + +trait MyDisplay { fn method(&self) { } } + +impl<'a, T: MyDisplay> MyDisplay for &'a mut T { } + +struct T; + +trait MPU { + type MpuConfig: MyDisplay = T; + //~^ ERROR the trait bound `T: MyDisplay` is not satisfied +} + +struct S; + +impl MPU for S { } +//~^ ERROR the trait bound `T: MyDisplay` is not satisfied + +trait MyWrite { + fn my_write(&self, _: &dyn MyDisplay) { } +} + +trait ProcessType { + fn process_detail_fmt(&self, _: &mut dyn MyWrite); +} + +struct Process; + +impl ProcessType for Process { + fn process_detail_fmt(&self, writer: &mut dyn MyWrite) + { + + let mut val: Option<::MpuConfig> = None; + let valref: &mut ::MpuConfig = val.as_mut().unwrap(); + + // // This causes a different ICE (but its similar if you squint right): + // // + // // `Unimplemented` selecting `Binder()` during codegen + // + writer.my_write(valref) + + // This one causes the ICE: + // FulfillmentError(Obligation(predicate=Binder(TraitPredicate()), + // depth=1),Unimplemented) + /*let closure = |config: &mut ::MpuConfig| writer.my_write(&config); + closure(valref);*/ + } +} + +fn create() -> &'static dyn ProcessType { + let input: Option<&mut Process> = None; + let process: &mut Process = input.unwrap(); + process +} + +pub fn main() { + create(); +} diff --git a/src/test/ui/associated-types/issue-65774-2.stderr b/src/test/ui/associated-types/issue-65774-2.stderr new file mode 100644 index 00000000000..cb515964226 --- /dev/null +++ b/src/test/ui/associated-types/issue-65774-2.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `T: MyDisplay` is not satisfied + --> $DIR/issue-65774-2.rs:10:21 + | +LL | trait MPU { + | --------- required by `MPU` +LL | type MpuConfig: MyDisplay = T; + | ^^^^^^^^^ the trait `MyDisplay` is not implemented for `T` + +error[E0277]: the trait bound `T: MyDisplay` is not satisfied + --> $DIR/issue-65774-2.rs:16:6 + | +LL | impl MPU for S { } + | ^^^ the trait `MyDisplay` is not implemented for `T` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index b299fc55841..35e418696f1 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}} +{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":{"_field0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},"NonJoint"],[{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]},"NonJoint"]]}}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs index 4a413381aa3..636fafc2bc4 100644 --- a/src/test/ui/async-await/async-fn-size-moved-locals.rs +++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs @@ -110,9 +110,9 @@ async fn mixed_sizes() { } fn main() { - assert_eq!(1028, std::mem::size_of_val(&single())); - assert_eq!(1032, std::mem::size_of_val(&single_with_noop())); - assert_eq!(3084, std::mem::size_of_val(&joined())); - assert_eq!(3084, std::mem::size_of_val(&joined_with_noop())); - assert_eq!(7188, std::mem::size_of_val(&mixed_sizes())); + assert_eq!(1025, std::mem::size_of_val(&single())); + assert_eq!(1026, std::mem::size_of_val(&single_with_noop())); + assert_eq!(3078, std::mem::size_of_val(&joined())); + assert_eq!(3079, std::mem::size_of_val(&joined_with_noop())); + assert_eq!(7181, std::mem::size_of_val(&mixed_sizes())); } diff --git a/src/test/ui/async-await/async-fn-size-uninit-locals.rs b/src/test/ui/async-await/async-fn-size-uninit-locals.rs index 0558084f4f8..d5d7b3fc3f0 100644 --- a/src/test/ui/async-await/async-fn-size-uninit-locals.rs +++ b/src/test/ui/async-await/async-fn-size-uninit-locals.rs @@ -95,9 +95,9 @@ async fn join_retval() -> Joiner { } fn main() { - assert_eq!(8, std::mem::size_of_val(&single())); - assert_eq!(12, std::mem::size_of_val(&single_with_noop())); - assert_eq!(3084, std::mem::size_of_val(&joined())); - assert_eq!(3084, std::mem::size_of_val(&joined_with_noop())); - assert_eq!(3080, std::mem::size_of_val(&join_retval())); + assert_eq!(2, std::mem::size_of_val(&single())); + assert_eq!(3, std::mem::size_of_val(&single_with_noop())); + assert_eq!(3078, std::mem::size_of_val(&joined())); + assert_eq!(3078, std::mem::size_of_val(&joined_with_noop())); + assert_eq!(3074, std::mem::size_of_val(&join_retval())); } diff --git a/src/test/ui/async-await/async-fn-size.rs b/src/test/ui/async-await/async-fn-size.rs index b313992db4e..0c1f3636446 100644 --- a/src/test/ui/async-await/async-fn-size.rs +++ b/src/test/ui/async-await/async-fn-size.rs @@ -86,13 +86,13 @@ async fn await3_level5() -> u8 { fn main() { assert_eq!(2, std::mem::size_of_val(&base())); - assert_eq!(8, std::mem::size_of_val(&await1_level1())); - assert_eq!(12, std::mem::size_of_val(&await2_level1())); - assert_eq!(12, std::mem::size_of_val(&await3_level1())); - assert_eq!(24, std::mem::size_of_val(&await3_level2())); - assert_eq!(36, std::mem::size_of_val(&await3_level3())); - assert_eq!(48, std::mem::size_of_val(&await3_level4())); - assert_eq!(60, std::mem::size_of_val(&await3_level5())); + assert_eq!(3, std::mem::size_of_val(&await1_level1())); + assert_eq!(4, std::mem::size_of_val(&await2_level1())); + assert_eq!(5, std::mem::size_of_val(&await3_level1())); + assert_eq!(8, std::mem::size_of_val(&await3_level2())); + assert_eq!(11, std::mem::size_of_val(&await3_level3())); + assert_eq!(14, std::mem::size_of_val(&await3_level4())); + assert_eq!(17, std::mem::size_of_val(&await3_level5())); assert_eq!(1, wait(base())); assert_eq!(1, wait(await1_level1())); diff --git a/src/test/ui/async-await/dont-print-desugared-async.stderr b/src/test/ui/async-await/dont-print-desugared-async.stderr index 2bf1e77f09b..d80467c7fa8 100644 --- a/src/test/ui/async-await/dont-print-desugared-async.stderr +++ b/src/test/ui/async-await/dont-print-desugared-async.stderr @@ -2,10 +2,7 @@ error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/dont-print-desugared-async.rs:5:20 | LL | async fn async_fn(&ref mut s: &[i32]) {} - | -^^^^^^^^^ - | || - | |cannot borrow as mutable through `&` reference - | help: consider changing this to be a mutable reference: `&mut ref mut s` + | ^^^^^^^^^ cannot borrow as mutable through `&` reference error: aborting due to previous error diff --git a/src/test/ui/async-await/expansion-in-attrs.rs b/src/test/ui/async-await/expansion-in-attrs.rs new file mode 100644 index 00000000000..af77c3463b5 --- /dev/null +++ b/src/test/ui/async-await/expansion-in-attrs.rs @@ -0,0 +1,13 @@ +// check-pass +// edition:2018 + +macro_rules! with_doc { + ($doc: expr) => { + #[doc = $doc] + async fn f() {} + }; +} + +with_doc!(concat!("")); + +fn main() {} diff --git a/src/test/ui/async-await/issue-54239-private-type-triggers-lint.rs b/src/test/ui/async-await/issue-54239-private-type-triggers-lint.rs new file mode 100644 index 00000000000..16cf7ad52e4 --- /dev/null +++ b/src/test/ui/async-await/issue-54239-private-type-triggers-lint.rs @@ -0,0 +1,17 @@ +// Regression test for #54239, shouldn't trigger lint. +// check-pass +// edition:2018 + +#![deny(missing_debug_implementations)] + +struct DontLookAtMe(i32); + +async fn secret() -> DontLookAtMe { + DontLookAtMe(41) +} + +pub async fn looking() -> i32 { // Shouldn't trigger lint here. + secret().await.0 +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-62097.nll.stderr b/src/test/ui/async-await/issues/issue-62097.nll.stderr index 0c64f90cb9f..2a399540e52 100644 --- a/src/test/ui/async-await/issues/issue-62097.nll.stderr +++ b/src/test/ui/async-await/issues/issue-62097.nll.stderr @@ -16,13 +16,13 @@ help: to force the closure to take ownership of `self` (and any other referenced LL | foo(move || self.bar()).await; | ^^^^^^^ -error[E0521]: borrowed data escapes outside of function +error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-62097.rs:13:9 | LL | pub async fn run_dummy_fn(&self) { - | ----- `self` is a reference that is only valid in the function body + | ----- `self` is a reference that is only valid in the associated function body LL | foo(|| self.bar()).await; - | ^^^^^^^^^^^^^^^^^^ `self` escapes the function body here + | ^^^^^^^^^^^^^^^^^^ `self` escapes the associated function body here error: aborting due to 2 previous errors diff --git a/src/test/ui/async-await/issues/issue-63388-1.nll.stderr b/src/test/ui/async-await/issues/issue-63388-1.nll.stderr index 4ae3971e90e..464459d2d61 100644 --- a/src/test/ui/async-await/issues/issue-63388-1.nll.stderr +++ b/src/test/ui/async-await/issues/issue-63388-1.nll.stderr @@ -1,11 +1,3 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/issue-63388-1.rs:12:10 - | -LL | ) -> &dyn Foo - | ^^^^^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#22r - error: lifetime may not live long enough --> $DIR/issue-63388-1.rs:13:5 | @@ -17,8 +9,7 @@ LL | ) -> &dyn Foo LL | / { LL | | foo LL | | } - | |_____^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` + | |_____^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs index b3c59734e03..57a9f175ca3 100644 --- a/src/test/ui/async-await/no-const-async.rs +++ b/src/test/ui/async-await/no-const-async.rs @@ -3,3 +3,4 @@ pub const async fn x() {} //~^ ERROR functions cannot be both `const` and `async` +//~| ERROR `impl Trait` in const fn is unstable diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr index f6ae0f1447c..4e59bb50767 100644 --- a/src/test/ui/async-await/no-const-async.stderr +++ b/src/test/ui/async-await/no-const-async.stderr @@ -1,11 +1,21 @@ error: functions cannot be both `const` and `async` - --> $DIR/no-const-async.rs:4:1 + --> $DIR/no-const-async.rs:4:5 | LL | pub const async fn x() {} - | ^^^^-----^-----^^^^^^^^^^ + | ----^^^^^-^^^^^---------- | | | | | `async` because of this | `const` because of this -error: aborting due to previous error +error[E0723]: `impl Trait` in const fn is unstable + --> $DIR/no-const-async.rs:4:24 + | +LL | pub const async fn x() {} + | ^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/async-await/no-unsafe-async.stderr b/src/test/ui/async-await/no-unsafe-async.stderr index 2651588d597..c97b4ff0f49 100644 --- a/src/test/ui/async-await/no-unsafe-async.stderr +++ b/src/test/ui/async-await/no-unsafe-async.stderr @@ -1,8 +1,13 @@ error: expected one of `extern` or `fn`, found keyword `async` --> $DIR/no-unsafe-async.rs:7:12 | +LL | impl S { + | - while parsing this item list starting here +LL | #[cfg(FALSE)] LL | unsafe async fn g() {} | ^^^^^ expected one of `extern` or `fn` +LL | } + | - the item list ends here error: expected one of `extern` or `fn`, found keyword `async` --> $DIR/no-unsafe-async.rs:11:8 diff --git a/src/test/ui/attributes/register-attr-tool-import.rs b/src/test/ui/attributes/register-attr-tool-import.rs index e01dc4dfa49..d3502c71f2d 100644 --- a/src/test/ui/attributes/register-attr-tool-import.rs +++ b/src/test/ui/attributes/register-attr-tool-import.rs @@ -1,4 +1,6 @@ // edition:2018 +// compile-flags: -Zsave-analysis +// ~^ Also regression test for #69588 #![feature(register_attr)] #![feature(register_tool)] diff --git a/src/test/ui/attributes/register-attr-tool-import.stderr b/src/test/ui/attributes/register-attr-tool-import.stderr index 59f5a8620ab..90b7e169a2f 100644 --- a/src/test/ui/attributes/register-attr-tool-import.stderr +++ b/src/test/ui/attributes/register-attr-tool-import.stderr @@ -1,35 +1,35 @@ error: cannot use an explicitly registered attribute through an import - --> $DIR/register-attr-tool-import.rs:12:3 + --> $DIR/register-attr-tool-import.rs:14:3 | LL | #[renamed_attr] | ^^^^^^^^^^^^ | note: the explicitly registered attribute imported here - --> $DIR/register-attr-tool-import.rs:9:5 + --> $DIR/register-attr-tool-import.rs:11:5 | LL | use attr as renamed_attr; // OK | ^^^^^^^^^^^^^^^^^^^^ error: cannot use a tool module through an import - --> $DIR/register-attr-tool-import.rs:13:3 + --> $DIR/register-attr-tool-import.rs:15:3 | LL | #[renamed_tool::attr] | ^^^^^^^^^^^^ | note: the tool module imported here - --> $DIR/register-attr-tool-import.rs:10:5 + --> $DIR/register-attr-tool-import.rs:12:5 | LL | use tool as renamed_tool; // OK | ^^^^^^^^^^^^^^^^^^^^ error: cannot use a tool module through an import - --> $DIR/register-attr-tool-import.rs:13:3 + --> $DIR/register-attr-tool-import.rs:15:3 | LL | #[renamed_tool::attr] | ^^^^^^^^^^^^ | note: the tool module imported here - --> $DIR/register-attr-tool-import.rs:10:5 + --> $DIR/register-attr-tool-import.rs:12:5 | LL | use tool as renamed_tool; // OK | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/auto-ref-slice-plus-ref.stderr b/src/test/ui/auto-ref-slice-plus-ref.stderr index a0739a7a90b..dc7deb8a7c7 100644 --- a/src/test/ui/auto-ref-slice-plus-ref.stderr +++ b/src/test/ui/auto-ref-slice-plus-ref.stderr @@ -2,11 +2,14 @@ error[E0599]: no method named `test_mut` found for struct `std::vec::Vec<{intege --> $DIR/auto-ref-slice-plus-ref.rs:7:7 | LL | a.test_mut(); - | ^^^^^^^^ help: there is a method with a similar name: `get_mut` + | ^^^^^^^^ help: there is an associated function with a similar name: `get_mut` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `test_mut`, perhaps you need to implement it: - candidate #1: `MyIter` +note: `MyIter` defines an item `test_mut`, perhaps you need to implement it + --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + | +LL | trait MyIter { + | ^^^^^^^^^^^^ error[E0599]: no method named `test` found for struct `std::vec::Vec<{integer}>` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:8:7 @@ -15,8 +18,11 @@ LL | a.test(); | ^^^^ method not found in `std::vec::Vec<{integer}>` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `test`, perhaps you need to implement it: - candidate #1: `MyIter` +note: `MyIter` defines an item `test`, perhaps you need to implement it + --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + | +LL | trait MyIter { + | ^^^^^^^^^^^^ error[E0599]: no method named `test` found for array `[{integer}; 1]` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:10:11 @@ -25,8 +31,11 @@ LL | ([1]).test(); | ^^^^ method not found in `[{integer}; 1]` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `test`, perhaps you need to implement it: - candidate #1: `MyIter` +note: `MyIter` defines an item `test`, perhaps you need to implement it + --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + | +LL | trait MyIter { + | ^^^^^^^^^^^^ error[E0599]: no method named `test` found for reference `&[{integer}; 1]` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:11:12 @@ -35,8 +44,11 @@ LL | (&[1]).test(); | ^^^^ method not found in `&[{integer}; 1]` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `test`, perhaps you need to implement it: - candidate #1: `MyIter` +note: `MyIter` defines an item `test`, perhaps you need to implement it + --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + | +LL | trait MyIter { + | ^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/auto-trait-validation.stderr b/src/test/ui/auto-trait-validation.stderr index 51422fab81f..4040e66c6af 100644 --- a/src/test/ui/auto-trait-validation.stderr +++ b/src/test/ui/auto-trait-validation.stderr @@ -1,20 +1,26 @@ error[E0567]: auto traits cannot have generic parameters - --> $DIR/auto-trait-validation.rs:3:1 + --> $DIR/auto-trait-validation.rs:3:19 | LL | auto trait Generic {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | -------^^^ help: remove the parameters + | | + | auto trait cannot have generic parameters error[E0568]: auto traits cannot have super traits - --> $DIR/auto-trait-validation.rs:5:1 + --> $DIR/auto-trait-validation.rs:5:20 | LL | auto trait Bound : Copy {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----- ^^^^ help: remove the super traits + | | + | auto trait cannot have super traits error[E0380]: auto traits cannot have methods or associated items - --> $DIR/auto-trait-validation.rs:7:1 + --> $DIR/auto-trait-validation.rs:7:25 | LL | auto trait MyTrait { fn foo() {} } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------- ^^^ + | | + | auto trait cannot have items error: aborting due to 3 previous errors diff --git a/src/test/ui/autoderef-full-lval.stderr b/src/test/ui/autoderef-full-lval.stderr index e2870ef8062..f094388794e 100644 --- a/src/test/ui/autoderef-full-lval.stderr +++ b/src/test/ui/autoderef-full-lval.stderr @@ -5,8 +5,6 @@ LL | let z: isize = a.x + b.y; | --- ^ --- std::boxed::Box | | | std::boxed::Box - | - = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box` error[E0369]: cannot add `std::boxed::Box` to `std::boxed::Box` --> $DIR/autoderef-full-lval.rs:21:33 @@ -15,8 +13,6 @@ LL | let answer: isize = forty.a + two.a; | ------- ^ ----- std::boxed::Box | | | std::boxed::Box - | - = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box` error: aborting due to 2 previous errors diff --git a/src/test/ui/binding/ambiguity-item.rs b/src/test/ui/binding/ambiguity-item.rs new file mode 100644 index 00000000000..10613cc6164 --- /dev/null +++ b/src/test/ui/binding/ambiguity-item.rs @@ -0,0 +1,18 @@ +// Identifier pattern referring to an ambiguity item is an error (issue #46079). + +mod m { + pub fn f() {} +} +use m::*; + +mod n { + pub fn f() {} +} +use n::*; // OK, no conflict with `use m::*;` + +fn main() { + let v = f; //~ ERROR `f` is ambiguous + match v { + f => {} //~ ERROR `f` is ambiguous + } +} diff --git a/src/test/ui/binding/ambiguity-item.stderr b/src/test/ui/binding/ambiguity-item.stderr new file mode 100644 index 00000000000..615193c0d02 --- /dev/null +++ b/src/test/ui/binding/ambiguity-item.stderr @@ -0,0 +1,41 @@ +error[E0659]: `f` is ambiguous (glob import vs glob import in the same module) + --> $DIR/ambiguity-item.rs:14:13 + | +LL | let v = f; + | ^ ambiguous name + | +note: `f` could refer to the function imported here + --> $DIR/ambiguity-item.rs:6:5 + | +LL | use m::*; + | ^^^^ + = help: consider adding an explicit import of `f` to disambiguate +note: `f` could also refer to the function imported here + --> $DIR/ambiguity-item.rs:11:5 + | +LL | use n::*; // OK, no conflict with `use m::*;` + | ^^^^ + = help: consider adding an explicit import of `f` to disambiguate + +error[E0659]: `f` is ambiguous (glob import vs glob import in the same module) + --> $DIR/ambiguity-item.rs:16:9 + | +LL | f => {} + | ^ ambiguous name + | +note: `f` could refer to the function imported here + --> $DIR/ambiguity-item.rs:6:5 + | +LL | use m::*; + | ^^^^ + = help: consider adding an explicit import of `f` to disambiguate +note: `f` could also refer to the function imported here + --> $DIR/ambiguity-item.rs:11:5 + | +LL | use n::*; // OK, no conflict with `use m::*;` + | ^^^^ + = help: consider adding an explicit import of `f` to disambiguate + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/binding/const-param.rs b/src/test/ui/binding/const-param.rs new file mode 100644 index 00000000000..3c7f4d071f6 --- /dev/null +++ b/src/test/ui/binding/const-param.rs @@ -0,0 +1,12 @@ +// Identifier pattern referring to a const generic parameter is an error (issue #68853). + +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete + +fn check() { + match 1 { + N => {} //~ ERROR const parameters cannot be referenced in patterns + _ => {} + } +} + +fn main() {} diff --git a/src/test/ui/binding/const-param.stderr b/src/test/ui/binding/const-param.stderr new file mode 100644 index 00000000000..25b1c75c9a0 --- /dev/null +++ b/src/test/ui/binding/const-param.stderr @@ -0,0 +1,17 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-param.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0158]: const parameters cannot be referenced in patterns + --> $DIR/const-param.rs:7:9 + | +LL | N => {} + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0158`. diff --git a/src/test/ui/binop/binop-bitxor-str.stderr b/src/test/ui/binop/binop-bitxor-str.stderr index 9a0d301d863..18c1ce0ff02 100644 --- a/src/test/ui/binop/binop-bitxor-str.stderr +++ b/src/test/ui/binop/binop-bitxor-str.stderr @@ -5,8 +5,6 @@ LL | fn main() { let x = "a".to_string() ^ "b".to_string(); } | --------------- ^ --------------- std::string::String | | | std::string::String - | - = note: an implementation of `std::ops::BitXor` might be missing for `std::string::String` error: aborting due to previous error diff --git a/src/test/ui/binop/binop-mul-bool.stderr b/src/test/ui/binop/binop-mul-bool.stderr index ade22025589..859c44a859e 100644 --- a/src/test/ui/binop/binop-mul-bool.stderr +++ b/src/test/ui/binop/binop-mul-bool.stderr @@ -5,8 +5,6 @@ LL | fn main() { let x = true * false; } | ---- ^ ----- bool | | | bool - | - = note: an implementation of `std::ops::Mul` might be missing for `bool` error: aborting due to previous error diff --git a/src/test/ui/binop/binop-typeck.stderr b/src/test/ui/binop/binop-typeck.stderr index ebf82079ef2..42d91081999 100644 --- a/src/test/ui/binop/binop-typeck.stderr +++ b/src/test/ui/binop/binop-typeck.stderr @@ -5,8 +5,6 @@ LL | let z = x + y; | - ^ - {integer} | | | bool - | - = note: an implementation of `std::ops::Add` might be missing for `bool` error: aborting due to previous error diff --git a/src/test/ui/blind/blind-item-block-middle.stderr b/src/test/ui/blind/blind-item-block-middle.stderr index 264e7fc8e73..d8d15615d7c 100644 --- a/src/test/ui/blind/blind-item-block-middle.stderr +++ b/src/test/ui/blind/blind-item-block-middle.stderr @@ -1,8 +1,15 @@ error[E0308]: mismatched types --> $DIR/blind-item-block-middle.rs:6:9 | +LL | mod foo { pub struct bar; } + | --------------- unit struct defined here +... LL | let bar = 5; - | ^^^ expected integer, found struct `foo::bar` + | ^^^ + | | + | expected integer, found struct `foo::bar` + | `bar` is interpreted as a unit struct, not a new binding + | help: introduce a new binding instead: `other_bar` error: aborting due to previous error diff --git a/src/test/ui/block-expr-precedence.stderr b/src/test/ui/block-expr-precedence.stderr index 1307b5d6ddd..decee1f2f16 100644 --- a/src/test/ui/block-expr-precedence.stderr +++ b/src/test/ui/block-expr-precedence.stderr @@ -4,5 +4,5 @@ warning: unnecessary trailing semicolons LL | if (true) { 12; };;; -num; | ^^ help: remove these semicolons | - = note: `#[warn(redundant_semicolon)]` on by default + = note: `#[warn(redundant_semicolons)]` on by default diff --git a/src/test/ui/block-result/issue-3563.stderr b/src/test/ui/block-result/issue-3563.stderr index be551f6e889..5255e48bee1 100644 --- a/src/test/ui/block-result/issue-3563.stderr +++ b/src/test/ui/block-result/issue-3563.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `b` found for reference `&Self` in the current sco --> $DIR/issue-3563.rs:3:17 | LL | || self.b() - | ^ help: there is a method with a similar name: `a` + | ^ help: there is an associated function with a similar name: `a` error: aborting due to previous error diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs new file mode 100644 index 00000000000..b67d494866b --- /dev/null +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs @@ -0,0 +1,224 @@ +// Tests using a combination of pattern features has the expected borrow checking behavior +#![feature(bindings_after_at)] +#![feature(or_patterns)] +#![feature(box_patterns)] + +#![feature(move_ref_pattern)] + +enum Test { + Foo, + Bar, + _Baz, +} + +// bindings_after_at + slice_patterns + +fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) { + match x { + a @ [.., _] => (), + _ => (), + }; + + &x; + //~^ ERROR borrow of moved value +} + +fn bindings_after_at_slice_patterns_borrows_binding_mut(mut x: [String; 4]) { + let r = match x { + ref mut foo @ [.., _] => Some(foo), + _ => None, + }; + + &x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_slice_patterns_borrows_slice_mut1(mut x: [String; 4]) { + let r = match x { + ref foo @ [.., ref mut bar] => (), + //~^ ERROR cannot borrow + _ => (), + }; + + drop(r); +} + +fn bindings_after_at_slice_patterns_borrows_slice_mut2(mut x: [String; 4]) { + let r = match x { + [ref foo @ .., ref bar] => Some(foo), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_slice_patterns_borrows_both(mut x: [String; 4]) { + let r = match x { + ref foo @ [.., ref bar] => Some(foo), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +// bindings_after_at + or_patterns + +fn bindings_after_at_or_patterns_move(x: Option) { + match x { + foo @ Some(Test::Foo | Test::Bar) => (), + _ => (), + } + + &x; + //~^ ERROR borrow of moved value +} + +fn bindings_after_at_or_patterns_borrows(mut x: Option) { + let r = match x { + ref foo @ Some(Test::Foo | Test::Bar) => Some(foo), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_or_patterns_borrows_mut(mut x: Option) { + let r = match x { + ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo), + _ => None, + }; + + &x; + //~^ ERROR cannot borrow + + drop(r); +} + +// bindings_after_at + box_patterns + +fn bindings_after_at_box_patterns_borrows_both(mut x: Option>) { + let r = match x { + ref foo @ Some(box ref s) => Some(foo), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_box_patterns_borrows_mut(mut x: Option>) { + match x { + ref foo @ Some(box ref mut s) => (), + //~^ ERROR cannot borrow + _ => (), + }; +} + +// bindings_after_at + slice_patterns + or_patterns + +fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option; 4]) { + match x { + a @ [.., Some(Test::Foo | Test::Bar)] => (), + _ => (), + }; + + &x; + //~^ ERROR borrow of moved value +} + +fn bindings_after_at_slice_patterns_or_patterns_borrows_binding(mut x: [Option; 4]) { + let r = match x { + ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_slice_patterns_or_patterns_borrows_slice(mut x: [Option; 4]) { + let r = match x { + ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +// bindings_after_at + slice_patterns + box_patterns + +fn bindings_after_at_slice_patterns_box_patterns_borrows(mut x: [Option>; 4]) { + let r = match x { + [_, ref a @ Some(box ref b), ..] => Some(a), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +// bindings_after_at + slice_patterns + or_patterns + box_patterns + +fn bindings_after_at_slice_patterns_or_patterns_box_patterns_borrows( + mut x: [Option>; 4] +) { + let r = match x { + [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_slice_patterns_or_patterns_box_patterns_borrows_mut( + mut x: [Option>; 4] +) { + let r = match x { + [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + _ => None, + }; + + &x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_slice_patterns_or_patterns_box_patterns_borrows_binding( + mut x: [Option>; 4] +) { + let r = match x { + ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn main() {} diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr new file mode 100644 index 00000000000..35ed2763c2b --- /dev/null +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -0,0 +1,208 @@ +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:40:9 + | +LL | ref foo @ [.., ref mut bar] => (), + | -------^^^^^^^^-----------^ + | | | + | | mutable borrow, by `bar`, occurs here + | immutable borrow, by `foo`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:124:9 + | +LL | ref foo @ Some(box ref mut s) => (), + | -------^^^^^^^^^^^^---------^ + | | | + | | mutable borrow, by `s`, occurs here + | immutable borrow, by `foo`, occurs here + +error[E0382]: borrow of moved value: `x` + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:22:5 + | +LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) { + | - move occurs because `x` has type `[std::string::String; 4]`, which does not implement the `Copy` trait +LL | match x { +LL | a @ [.., _] => (), + | ----------- value moved here +... +LL | &x; + | ^^ value borrowed here after move + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:32:5 + | +LL | ref mut foo @ [.., _] => Some(foo), + | --------------------- mutable borrow occurs here +... +LL | &x; + | ^^ immutable borrow occurs here +... +LL | drop(r); + | - mutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:54:5 + | +LL | [ref foo @ .., ref bar] => Some(foo), + | ------------ immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:66:5 + | +LL | ref foo @ [.., ref bar] => Some(foo), + | ----------------------- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0382]: borrow of moved value: `x` + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:80:5 + | +LL | fn bindings_after_at_or_patterns_move(x: Option) { + | - move occurs because `x` has type `std::option::Option`, which does not implement the `Copy` trait +LL | match x { +LL | foo @ Some(Test::Foo | Test::Bar) => (), + | --------------------------------- + | | + | value moved here + | value moved here +... +LL | &x; + | ^^ value borrowed here after move + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:90:5 + | +LL | ref foo @ Some(Test::Foo | Test::Bar) => Some(foo), + | ------------------------------------- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:102:5 + | +LL | ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo), + | ----------------------------------------- mutable borrow occurs here +... +LL | &x; + | ^^ immutable borrow occurs here +... +LL | drop(r); + | - mutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:116:5 + | +LL | ref foo @ Some(box ref s) => Some(foo), + | ------------------------- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0382]: borrow of moved value: `x` + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:138:5 + | +LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option; 4]) { + | - move occurs because `x` has type `[std::option::Option; 4]`, which does not implement the `Copy` trait +LL | match x { +LL | a @ [.., Some(Test::Foo | Test::Bar)] => (), + | ------------------------------------- + | | + | value moved here + | value moved here +... +LL | &x; + | ^^ value borrowed here after move + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:148:5 + | +LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a), + | ------------------------------------------------- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:160:5 + | +LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b), + | ---------- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:174:5 + | +LL | [_, ref a @ Some(box ref b), ..] => Some(a), + | ----------------------- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:190:5 + | +LL | [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + | ------------------------------------------- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:204:5 + | +LL | [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + | ----------------------------------------------- mutable borrow occurs here +... +LL | &x; + | ^^ immutable borrow occurs here +... +LL | drop(r); + | - mutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:218:5 + | +LL | ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + | ------------------------------------------------------------ immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error: aborting due to 17 previous errors + +Some errors have detailed explanations: E0382, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs new file mode 100644 index 00000000000..57198cb95e7 --- /dev/null +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs @@ -0,0 +1,14 @@ +#![feature(unboxed_closures)] + +// Tests that we can't assign to or mutably borrow upvars from `Fn` +// closures (issue #17780) + +fn main() {} + +fn bar() -> impl Fn() -> usize { + let mut x = 0; + move || { + x += 1; //~ ERROR cannot assign + x + } +} diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr new file mode 100644 index 00000000000..003c40d2773 --- /dev/null +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr @@ -0,0 +1,16 @@ +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation-impl-trait.rs:11:9 + | +LL | fn bar() -> impl Fn() -> usize { + | --- ------------------ change this to return `FnMut` instead of `Fn` +LL | let mut x = 0; +LL | / move || { +LL | | x += 1; + | | ^^^^^^ cannot assign +LL | | x +LL | | } + | |_____- in this closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs index 62e27bcf164..e2f016614bf 100644 --- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.rs @@ -3,10 +3,16 @@ // Tests that we can't assign to or mutably borrow upvars from `Fn` // closures (issue #17780) -fn set(x: &mut usize) { *x = 5; } +fn set(x: &mut usize) { + *x = 5; +} -fn to_fn>(f: F) -> F { f } -fn to_fn_mut>(f: F) -> F { f } +fn to_fn>(f: F) -> F { + f +} +fn to_fn_mut>(f: F) -> F { + f +} fn main() { // By-ref captures @@ -33,7 +39,11 @@ fn main() { let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow let mut z = 0; - let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign + let _h = to_fn_mut(move || { + set(&mut z); + to_fn(move || z = 42); + //~^ ERROR cannot assign + }); } } @@ -44,11 +54,3 @@ fn foo() -> Box usize> { x }) } - -fn bar() -> impl Fn() -> usize { - let mut x = 0; - move || { - x += 1; //~ ERROR cannot assign - x - } -} diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr index 3046b047d00..a28cb7431e6 100644 --- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr +++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr @@ -1,8 +1,8 @@ error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:15:27 + --> $DIR/borrow-immutable-upvar-mutation.rs:21:27 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... LL | let _f = to_fn(|| x = 42); | ----- ^^^^^^ cannot assign @@ -10,10 +10,10 @@ LL | let _f = to_fn(|| x = 42); | expects `Fn` instead of `FnMut` error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:18:31 + --> $DIR/borrow-immutable-upvar-mutation.rs:24:31 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... LL | let _g = to_fn(|| set(&mut y)); | ----- ^^^^^^ cannot borrow as mutable @@ -21,10 +21,10 @@ LL | let _g = to_fn(|| set(&mut y)); | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:23:22 + --> $DIR/borrow-immutable-upvar-mutation.rs:29:22 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... LL | to_fn(|| z = 42); | ----- ^^^^^^ cannot assign @@ -32,10 +32,10 @@ LL | to_fn(|| z = 42); | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:30:32 + --> $DIR/borrow-immutable-upvar-mutation.rs:36:32 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... LL | let _f = to_fn(move || x = 42); | ----- ^^^^^^ cannot assign @@ -43,10 +43,10 @@ LL | let _f = to_fn(move || x = 42); | expects `Fn` instead of `FnMut` error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:33:36 + --> $DIR/borrow-immutable-upvar-mutation.rs:39:36 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... LL | let _g = to_fn(move || set(&mut y)); | ----- ^^^^^^ cannot borrow as mutable @@ -54,18 +54,18 @@ LL | let _g = to_fn(move || set(&mut y)); | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:36:65 + --> $DIR/borrow-immutable-upvar-mutation.rs:44:27 | -LL | fn to_fn>(f: F) -> F { f } - | - change this to accept `FnMut` instead of `Fn` +LL | fn to_fn>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` ... -LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); - | ----- ^^^^^^ cannot assign - | | - | expects `Fn` instead of `FnMut` +LL | to_fn(move || z = 42); + | ----- ^^^^^^ cannot assign + | | + | expects `Fn` instead of `FnMut` error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:43:9 + --> $DIR/borrow-immutable-upvar-mutation.rs:53:9 | LL | fn foo() -> Box usize> { | --- ---------------------- change this to return `FnMut` instead of `Fn` @@ -78,20 +78,7 @@ LL | | x LL | | }) | |_____- in this closure -error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure - --> $DIR/borrow-immutable-upvar-mutation.rs:51:9 - | -LL | fn bar() -> impl Fn() -> usize { - | --- ------------------ change this to return `FnMut` instead of `Fn` -LL | let mut x = 0; -LL | / move || { -LL | | x += 1; - | | ^^^^^^ cannot assign -LL | | x -LL | | } - | |_____- in this closure - -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0594, E0596. For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/move-error-snippets.stderr b/src/test/ui/borrowck/move-error-snippets.stderr index e0acd459571..58a90b2fca2 100644 --- a/src/test/ui/borrowck/move-error-snippets.stderr +++ b/src/test/ui/borrowck/move-error-snippets.stderr @@ -1,14 +1,16 @@ error[E0507]: cannot move out of static item `D` - --> $DIR/move-error-snippets.rs:16:18 + --> $DIR/move-error-snippets-ext.rs:5:17 | -LL | | #[macro_use] - | |__________________^ move occurs because `D` has type `A`, which does not implement the `Copy` trait -... -LL | aaa!(D); - | __________________^ -... -LL | sss!(); - | ------- in this macro invocation +LL | let a = $c; + | ^^ + | | + | move occurs because `D` has type `A`, which does not implement the `Copy` trait + | help: consider borrowing here: `&$c` + | + ::: $DIR/move-error-snippets.rs:21:1 + | +LL | sss!(); + | ------- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr index 2fdb3836dd9..999a5839ba6 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr @@ -4,7 +4,7 @@ error[E0310]: the parameter type `T` may not live long enough LL | impl Foo for T { } | -- ^^^ | | - | help: consider adding an explicit lifetime bound `T: 'static`... + | help: consider adding an explicit lifetime bound...: `T: 'static +` | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/builtin-superkinds-self-type.rs:10:16 diff --git a/src/test/ui/c-variadic/variadic-ffi-1.rs b/src/test/ui/c-variadic/variadic-ffi-1.rs index 6a3ff24b674..e7197a9d168 100644 --- a/src/test/ui/c-variadic/variadic-ffi-1.rs +++ b/src/test/ui/c-variadic/variadic-ffi-1.rs @@ -13,8 +13,8 @@ extern "C" fn bar(f: isize, x: u8) {} fn main() { unsafe { - foo(); //~ ERROR this function takes at least 2 parameters but 0 parameters were supplied - foo(1); //~ ERROR this function takes at least 2 parameters but 1 parameter was supplied + foo(); //~ ERROR this function takes at least 2 arguments but 0 arguments were supplied + foo(1); //~ ERROR this function takes at least 2 arguments but 1 argument was supplied let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~ ERROR mismatched types let y: extern "C" fn(f: isize, x: u8, ...) = bar; //~ ERROR mismatched types diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr index 05d839a0c55..318b8aabafb 100644 --- a/src/test/ui/c-variadic/variadic-ffi-1.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr @@ -4,23 +4,27 @@ error[E0045]: C-variadic function must have C or cdecl calling convention LL | fn printf(_: *const u8, ...); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention -error[E0060]: this function takes at least 2 parameters but 0 parameters were supplied +error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied --> $DIR/variadic-ffi-1.rs:16:9 | LL | fn foo(f: isize, x: u8, ...); | ----------------------------- defined here ... LL | foo(); - | ^^^^^ expected at least 2 parameters + | ^^^-- supplied 0 arguments + | | + | expected at least 2 arguments -error[E0060]: this function takes at least 2 parameters but 1 parameter was supplied +error[E0060]: this function takes at least 2 arguments but 1 argument was supplied --> $DIR/variadic-ffi-1.rs:17:9 | LL | fn foo(f: isize, x: u8, ...); | ----------------------------- defined here ... LL | foo(1); - | ^^^^^^ expected at least 2 parameters + | ^^^ - supplied 1 argument + | | + | expected at least 2 arguments error[E0308]: mismatched types --> $DIR/variadic-ffi-1.rs:19:56 diff --git a/src/test/ui/chalkify/builtin-copy-clone.rs b/src/test/ui/chalkify/builtin-copy-clone.rs deleted file mode 100644 index d403514b553..00000000000 --- a/src/test/ui/chalkify/builtin-copy-clone.rs +++ /dev/null @@ -1,44 +0,0 @@ -// run-pass -// compile-flags: -Z chalk - -// Test that `Clone` is correctly implemented for builtin types. - -#[derive(Copy, Clone)] -struct S(i32); - -fn test_clone(arg: T) { - let _ = arg.clone(); -} - -fn test_copy(arg: T) { - let _ = arg; - let _ = arg; -} - -fn test_copy_clone(arg: T) { - test_copy(arg); - test_clone(arg); -} - -fn foo() { } - -fn main() { - test_copy_clone(foo); - let f: fn() = foo; - test_copy_clone(f); - // FIXME: add closures when they're considered WF - test_copy_clone([1; 56]); - test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)); - test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, true, 'a', 1.1)); - test_copy_clone(()); - test_copy_clone(((1, 1), (1, 1, 1), (1.1, 1, 1, 'a'), ())); - - let a = ( - (S(1), S(0)), - ( - (S(0), S(0), S(1)), - S(0) - ) - ); - test_copy_clone(a); -} diff --git a/src/test/ui/chalkify/inherent_impl.rs b/src/test/ui/chalkify/inherent_impl.rs deleted file mode 100644 index 44e120c1eeb..00000000000 --- a/src/test/ui/chalkify/inherent_impl.rs +++ /dev/null @@ -1,42 +0,0 @@ -// run-pass -// compile-flags: -Z chalk - -trait Foo { } - -impl Foo for i32 { } - -struct S { - x: T, -} - -fn only_foo(_x: &T) { } - -impl S { - // Test that we have the correct environment inside an inherent method. - fn dummy_foo(&self) { - only_foo(&self.x) - } -} - -trait Bar { } -impl Bar for u32 { } - -fn only_bar() { } - -impl S { - // Test that the environment of `dummy_bar` adds up with the environment - // of the inherent impl. - fn dummy_bar(&self) { - only_foo(&self.x); - only_bar::(); - } -} - -fn main() { - let s = S { - x: 5, - }; - - s.dummy_foo(); - s.dummy_bar::(); -} diff --git a/src/test/ui/chalkify/lower_env1.rs b/src/test/ui/chalkify/lower_env1.rs deleted file mode 100644 index afb6bddbf26..00000000000 --- a/src/test/ui/chalkify/lower_env1.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![feature(rustc_attrs)] -#![allow(dead_code)] - -trait Foo { } - -#[rustc_dump_program_clauses] //~ ERROR program clause dump -trait Bar where Self: Foo { } - -#[rustc_dump_env_program_clauses] //~ ERROR program clause dump -fn bar() { -} - -fn main() { -} diff --git a/src/test/ui/chalkify/lower_env1.stderr b/src/test/ui/chalkify/lower_env1.stderr deleted file mode 100644 index bc426e0707b..00000000000 --- a/src/test/ui/chalkify/lower_env1.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: program clause dump - --> $DIR/lower_env1.rs:6:1 - | -LL | #[rustc_dump_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall { FromEnv(Self: Foo) :- FromEnv(Self: Bar). } - = note: forall { Implemented(Self: Bar) :- FromEnv(Self: Bar). } - = note: forall { WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo). } - -error: program clause dump - --> $DIR/lower_env1.rs:9:1 - | -LL | #[rustc_dump_env_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall { FromEnv(Self: Foo) :- FromEnv(Self: Bar). } - = note: forall { Implemented(Self: Bar) :- FromEnv(Self: Bar). } - = note: forall { Implemented(Self: Foo) :- FromEnv(Self: Foo). } - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/chalkify/lower_env2.rs b/src/test/ui/chalkify/lower_env2.rs deleted file mode 100644 index a067575a9cf..00000000000 --- a/src/test/ui/chalkify/lower_env2.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(rustc_attrs)] -#![allow(dead_code)] - -trait Foo { } - -#[rustc_dump_program_clauses] //~ ERROR program clause dump -struct S<'a, T: ?Sized> where T: Foo { - data: &'a T, -} - -#[rustc_dump_env_program_clauses] //~ ERROR program clause dump -fn bar(_x: S<'_, T>) { // note that we have an implicit `T: Sized` bound -} - -fn main() { -} diff --git a/src/test/ui/chalkify/lower_env2.stderr b/src/test/ui/chalkify/lower_env2.stderr deleted file mode 100644 index 613a568a854..00000000000 --- a/src/test/ui/chalkify/lower_env2.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: program clause dump - --> $DIR/lower_env2.rs:6:1 - | -LL | #[rustc_dump_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall<'a, T> { FromEnv(T: Foo) :- FromEnv(S<'a, T>). } - = note: forall<'a, T> { TypeOutlives(T: 'a) :- FromEnv(S<'a, T>). } - = note: forall<'a, T> { WellFormed(S<'a, T>) :- WellFormed(T: Foo), TypeOutlives(T: 'a). } - -error: program clause dump - --> $DIR/lower_env2.rs:11:1 - | -LL | #[rustc_dump_env_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall<'a, T> { FromEnv(T: Foo) :- FromEnv(S<'a, T>). } - = note: forall<'a, T> { TypeOutlives(T: 'a) :- FromEnv(S<'a, T>). } - = note: forall { Implemented(Self: Foo) :- FromEnv(Self: Foo). } - = note: forall { Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized). } - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/chalkify/lower_env3.rs b/src/test/ui/chalkify/lower_env3.rs deleted file mode 100644 index 61ed3cbb277..00000000000 --- a/src/test/ui/chalkify/lower_env3.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(rustc_attrs)] -#![allow(dead_code)] - -trait Foo { - #[rustc_dump_env_program_clauses] //~ ERROR program clause dump - fn foo(&self); -} - -impl Foo for T where T: Clone { - #[rustc_dump_env_program_clauses] //~ ERROR program clause dump - fn foo(&self) { - } -} - -fn main() { -} diff --git a/src/test/ui/chalkify/lower_env3.stderr b/src/test/ui/chalkify/lower_env3.stderr deleted file mode 100644 index a1fc83bfea8..00000000000 --- a/src/test/ui/chalkify/lower_env3.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: program clause dump - --> $DIR/lower_env3.rs:5:5 - | -LL | #[rustc_dump_env_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall { Implemented(Self: Foo) :- FromEnv(Self: Foo). } - -error: program clause dump - --> $DIR/lower_env3.rs:10:5 - | -LL | #[rustc_dump_env_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall { FromEnv(Self: std::marker::Sized) :- FromEnv(Self: std::clone::Clone). } - = note: forall { Implemented(Self: std::clone::Clone) :- FromEnv(Self: std::clone::Clone). } - = note: forall { Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized). } - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/chalkify/lower_impl.rs b/src/test/ui/chalkify/lower_impl.rs deleted file mode 100644 index 1bd44a9f498..00000000000 --- a/src/test/ui/chalkify/lower_impl.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![feature(rustc_attrs)] - -trait Foo { } - -#[rustc_dump_program_clauses] //~ ERROR program clause dump -impl Foo for T where T: Iterator { } - -trait Bar { - type Assoc; -} - -impl Bar for T where T: Iterator { - #[rustc_dump_program_clauses] //~ ERROR program clause dump - type Assoc = Vec; -} - -fn main() { - println!("hello"); -} diff --git a/src/test/ui/chalkify/lower_impl.stderr b/src/test/ui/chalkify/lower_impl.stderr deleted file mode 100644 index d6827fbff3d..00000000000 --- a/src/test/ui/chalkify/lower_impl.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: program clause dump - --> $DIR/lower_impl.rs:5:1 - | -LL | #[rustc_dump_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall { Implemented(T: Foo) :- ProjectionEq(::Item == i32), TypeOutlives(T: 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized). } - -error: program clause dump - --> $DIR/lower_impl.rs:13:5 - | -LL | #[rustc_dump_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall { Normalize(::Assoc -> std::vec::Vec) :- Implemented(T: Bar). } - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/chalkify/lower_struct.rs b/src/test/ui/chalkify/lower_struct.rs deleted file mode 100644 index aecccea5c14..00000000000 --- a/src/test/ui/chalkify/lower_struct.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(rustc_attrs)] - -#[rustc_dump_program_clauses] //~ ERROR program clause dump -struct Foo<'a, T> where Box: Clone { - _x: std::marker::PhantomData<&'a T>, -} - -fn main() { } diff --git a/src/test/ui/chalkify/lower_struct.stderr b/src/test/ui/chalkify/lower_struct.stderr deleted file mode 100644 index 0331c2fca16..00000000000 --- a/src/test/ui/chalkify/lower_struct.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: program clause dump - --> $DIR/lower_struct.rs:3:1 - | -LL | #[rustc_dump_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall<'a, T> { FromEnv(T: std::marker::Sized) :- FromEnv(Foo<'a, T>). } - = note: forall<'a, T> { FromEnv(std::boxed::Box: std::clone::Clone) :- FromEnv(Foo<'a, T>). } - = note: forall<'a, T> { TypeOutlives(T: 'a) :- FromEnv(Foo<'a, T>). } - = note: forall<'a, T> { WellFormed(Foo<'a, T>) :- WellFormed(T: std::marker::Sized), WellFormed(std::boxed::Box: std::clone::Clone), TypeOutlives(T: 'a). } - -error: aborting due to previous error - diff --git a/src/test/ui/chalkify/lower_trait.rs b/src/test/ui/chalkify/lower_trait.rs deleted file mode 100644 index 0e1956022f9..00000000000 --- a/src/test/ui/chalkify/lower_trait.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(rustc_attrs)] - -trait Bar { } - -#[rustc_dump_program_clauses] //~ ERROR program clause dump -trait Foo { - #[rustc_dump_program_clauses] //~ ERROR program clause dump - type Assoc: Bar + ?Sized; -} - -fn main() { - println!("hello"); -} diff --git a/src/test/ui/chalkify/lower_trait.stderr b/src/test/ui/chalkify/lower_trait.stderr deleted file mode 100644 index ed3bded398a..00000000000 --- a/src/test/ui/chalkify/lower_trait.stderr +++ /dev/null @@ -1,24 +0,0 @@ -error: program clause dump - --> $DIR/lower_trait.rs:5:1 - | -LL | #[rustc_dump_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall { FromEnv(>::Assoc: Bar) :- FromEnv(Self: Foo). } - = note: forall { FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo). } - = note: forall { Implemented(Self: Foo) :- FromEnv(Self: Foo). } - = note: forall { WellFormed(Self: Foo) :- Implemented(Self: Foo), WellFormed(S: std::marker::Sized), WellFormed(>::Assoc: Bar). } - -error: program clause dump - --> $DIR/lower_trait.rs:7:5 - | -LL | #[rustc_dump_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall { ProjectionEq(>::Assoc == ^3) :- Normalize(>::Assoc -> ^3). } - = note: forall { FromEnv(Self: Foo) :- FromEnv(Unnormalized(>::Assoc)). } - = note: forall { ProjectionEq(>::Assoc == Unnormalized(>::Assoc)). } - = note: forall { WellFormed(Unnormalized(>::Assoc)) :- WellFormed(Self: Foo). } - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/chalkify/lower_trait_higher_rank.rs b/src/test/ui/chalkify/lower_trait_higher_rank.rs deleted file mode 100644 index 715f09632bd..00000000000 --- a/src/test/ui/chalkify/lower_trait_higher_rank.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(rustc_attrs)] - -#[rustc_dump_program_clauses] //~ ERROR program clause dump -trait Foo where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8 -{ -} - -fn main() { - println!("hello"); -} diff --git a/src/test/ui/chalkify/lower_trait_higher_rank.stderr b/src/test/ui/chalkify/lower_trait_higher_rank.stderr deleted file mode 100644 index 79bbc9fa6b3..00000000000 --- a/src/test/ui/chalkify/lower_trait_higher_rank.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error: program clause dump - --> $DIR/lower_trait_higher_rank.rs:3:1 - | -LL | #[rustc_dump_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall<'a, Self, F> { FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo). } - = note: forall<'a, Self, F> { ProjectionEq(>::Output == &'a u8) :- FromEnv(Self: Foo). } - = note: forall { Implemented(Self: Foo) :- FromEnv(Self: Foo). } - = note: forall { WellFormed(Self: Foo) :- Implemented(Self: Foo), forall<'a> { WellFormed(F: std::ops::Fn<(&'a (u8, u16),)>) }, forall<'a> { ProjectionEq(>::Output == &'a u8) }. } - -error: aborting due to previous error - diff --git a/src/test/ui/chalkify/lower_trait_where_clause.rs b/src/test/ui/chalkify/lower_trait_where_clause.rs deleted file mode 100644 index 78fa39f1dc1..00000000000 --- a/src/test/ui/chalkify/lower_trait_where_clause.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![feature(rustc_attrs)] - -use std::borrow::Borrow; - -#[rustc_dump_program_clauses] //~ ERROR program clause dump -trait Foo<'a, 'b, T, U> -where - T: Borrow + ?Sized, - U: ?Sized + 'b, - 'a: 'b, - Box:, // NOTE(#53696) this checks an empty list of bounds. -{ -} - -fn main() { - println!("hello"); -} diff --git a/src/test/ui/chalkify/lower_trait_where_clause.stderr b/src/test/ui/chalkify/lower_trait_where_clause.stderr deleted file mode 100644 index 408f3712a70..00000000000 --- a/src/test/ui/chalkify/lower_trait_where_clause.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: program clause dump - --> $DIR/lower_trait_where_clause.rs:5:1 - | -LL | #[rustc_dump_program_clauses] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: forall<'a, 'b, Self, T, U> { FromEnv(T: std::borrow::Borrow) :- FromEnv(Self: Foo<'a, 'b, T, U>). } - = note: forall<'a, 'b, Self, T, U> { Implemented(Self: Foo<'a, 'b, T, U>) :- FromEnv(Self: Foo<'a, 'b, T, U>). } - = note: forall<'a, 'b, Self, T, U> { RegionOutlives('a: 'b) :- FromEnv(Self: Foo<'a, 'b, T, U>). } - = note: forall<'a, 'b, Self, T, U> { TypeOutlives(U: 'b) :- FromEnv(Self: Foo<'a, 'b, T, U>). } - = note: forall<'a, 'b, Self, T, U> { TypeOutlives(std::boxed::Box: ') :- FromEnv(Self: Foo<'a, 'b, T, U>). } - = note: forall<'a, 'b, Self, T, U> { WellFormed(Self: Foo<'a, 'b, T, U>) :- Implemented(Self: Foo<'a, 'b, T, U>), WellFormed(T: std::borrow::Borrow), TypeOutlives(U: 'b), RegionOutlives('a: 'b), TypeOutlives(std::boxed::Box: '). } - -error: aborting due to previous error - diff --git a/src/test/ui/chalkify/projection.rs b/src/test/ui/chalkify/projection.rs deleted file mode 100644 index d6a8dd7a4a2..00000000000 --- a/src/test/ui/chalkify/projection.rs +++ /dev/null @@ -1,25 +0,0 @@ -// run-pass -// compile-flags: -Z chalk - -trait Foo { } - -trait Bar { - type Item: Foo; -} - -impl Foo for i32 { } -impl Bar for i32 { - type Item = i32; -} - -fn only_foo() { } - -fn only_bar() { - // `T` implements `Bar` hence `::Item` must also implement `Bar` - only_foo::() -} - -fn main() { - only_bar::(); - only_foo::<::Item>(); -} diff --git a/src/test/ui/chalkify/super_trait.rs b/src/test/ui/chalkify/super_trait.rs deleted file mode 100644 index eeff9fd9b80..00000000000 --- a/src/test/ui/chalkify/super_trait.rs +++ /dev/null @@ -1,19 +0,0 @@ -// run-pass -// compile-flags: -Z chalk - -trait Foo { } -trait Bar: Foo { } - -impl Foo for i32 { } -impl Bar for i32 { } - -fn only_foo() { } - -fn only_bar() { - // `T` implements `Bar` hence `T` must also implement `Foo` - only_foo::() -} - -fn main() { - only_bar::() -} diff --git a/src/test/ui/chalkify/trait_implied_bound.rs b/src/test/ui/chalkify/trait_implied_bound.rs deleted file mode 100644 index 8a2e1cf5990..00000000000 --- a/src/test/ui/chalkify/trait_implied_bound.rs +++ /dev/null @@ -1,18 +0,0 @@ -// run-pass -// compile-flags: -Z chalk - -trait Foo { } -trait Bar where U: Foo { } - -impl Foo for i32 { } -impl Bar for i32 { } - -fn only_foo() { } - -fn only_bar>() { - only_foo::() -} - -fn main() { - only_bar::() -} diff --git a/src/test/ui/chalkify/type_implied_bound.rs b/src/test/ui/chalkify/type_implied_bound.rs deleted file mode 100644 index 8673f5319bd..00000000000 --- a/src/test/ui/chalkify/type_implied_bound.rs +++ /dev/null @@ -1,29 +0,0 @@ -// run-pass -// compile-flags: -Z chalk - -trait Eq { } -trait Hash: Eq { } - -impl Eq for i32 { } -impl Hash for i32 { } - -struct Set { - _x: T, -} - -fn only_eq() { } - -fn take_a_set(_: &Set) { - // `Set` is an input type of `take_a_set`, hence we know that - // `T` must implement `Hash`, and we know in turn that `T` must - // implement `Eq`. - only_eq::() -} - -fn main() { - let set = Set { - _x: 5, - }; - - take_a_set(&set); -} diff --git a/src/test/ui/chalkify/type_inference.rs b/src/test/ui/chalkify/type_inference.rs deleted file mode 100644 index 62a53ec0317..00000000000 --- a/src/test/ui/chalkify/type_inference.rs +++ /dev/null @@ -1,26 +0,0 @@ -// compile-flags: -Z chalk - -trait Foo { } -impl Foo for i32 { } - -trait Bar { } -impl Bar for i32 { } -impl Bar for u32 { } - -fn only_foo(_x: T) { } - -fn only_bar(_x: T) { } - -fn main() { - let x = 5.0; - - // The only type which implements `Foo` is `i32`, so the chalk trait solver - // is expecting a variable of type `i32`. This behavior differs from the - // old-style trait solver. I guess this will change, that's why I'm - // adding that test. - only_foo(x); //~ ERROR mismatched types - - // Here we have two solutions so we get back the behavior of the old-style - // trait solver. - only_bar(x); //~ ERROR the trait bound `{float}: Bar` is not satisfied -} diff --git a/src/test/ui/chalkify/type_inference.stderr b/src/test/ui/chalkify/type_inference.stderr deleted file mode 100644 index b8152caf3d2..00000000000 --- a/src/test/ui/chalkify/type_inference.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/type_inference.rs:21:14 - | -LL | only_foo(x); - | ^ expected `i32`, found floating-point number - -error[E0277]: the trait bound `{float}: Bar` is not satisfied - --> $DIR/type_inference.rs:25:5 - | -LL | fn only_bar(_x: T) { } - | -------- --- required by this bound in `only_bar` -... -LL | only_bar(x); - | ^^^^^^^^ the trait `Bar` is not implemented for `{float}` - | - = help: the following implementations were found: - - - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/coherence/coherence-negative-impls-safe.stderr b/src/test/ui/coherence/coherence-negative-impls-safe.stderr index 4db66af6783..1bd37f39590 100644 --- a/src/test/ui/coherence/coherence-negative-impls-safe.stderr +++ b/src/test/ui/coherence/coherence-negative-impls-safe.stderr @@ -1,9 +1,10 @@ error[E0198]: negative impls cannot be unsafe - --> $DIR/coherence-negative-impls-safe.rs:7:1 + --> $DIR/coherence-negative-impls-safe.rs:7:13 | LL | unsafe impl !Send for TestType {} - | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | + | ------ -^^^^ + | | | + | | negative because of this | unsafe because of this error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg_accessible-input-validation.rs b/src/test/ui/conditional-compilation/cfg_accessible-input-validation.rs new file mode 100644 index 00000000000..c51c908a426 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-input-validation.rs @@ -0,0 +1,24 @@ +#![feature(cfg_accessible)] + +#[cfg_accessible] //~ ERROR malformed `cfg_accessible` attribute input +struct S1; + +#[cfg_accessible = "value"] //~ ERROR malformed `cfg_accessible` attribute input +struct S2; + +#[cfg_accessible()] //~ ERROR `cfg_accessible` path is not specified +struct S3; + +#[cfg_accessible(std, core)] //~ ERROR multiple `cfg_accessible` paths are specified +struct S4; + +#[cfg_accessible("std")] //~ ERROR `cfg_accessible` path cannot be a literal +struct S5; + +#[cfg_accessible(std = "value")] //~ ERROR `cfg_accessible` path cannot accept arguments +struct S6; + +#[cfg_accessible(std(value))] //~ ERROR `cfg_accessible` path cannot accept arguments +struct S7; + +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg_accessible-input-validation.stderr b/src/test/ui/conditional-compilation/cfg_accessible-input-validation.stderr new file mode 100644 index 00000000000..86706c76635 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-input-validation.stderr @@ -0,0 +1,44 @@ +error: malformed `cfg_accessible` attribute input + --> $DIR/cfg_accessible-input-validation.rs:3:1 + | +LL | #[cfg_accessible] + | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[cfg_accessible(path)]` + +error: malformed `cfg_accessible` attribute input + --> $DIR/cfg_accessible-input-validation.rs:6:1 + | +LL | #[cfg_accessible = "value"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[cfg_accessible(path)]` + +error: `cfg_accessible` path is not specified + --> $DIR/cfg_accessible-input-validation.rs:9:1 + | +LL | #[cfg_accessible()] + | ^^^^^^^^^^^^^^^^^^^ + +error: multiple `cfg_accessible` paths are specified + --> $DIR/cfg_accessible-input-validation.rs:12:23 + | +LL | #[cfg_accessible(std, core)] + | ^^^^ + +error: `cfg_accessible` path cannot be a literal + --> $DIR/cfg_accessible-input-validation.rs:15:18 + | +LL | #[cfg_accessible("std")] + | ^^^^^ + +error: `cfg_accessible` path cannot accept arguments + --> $DIR/cfg_accessible-input-validation.rs:18:18 + | +LL | #[cfg_accessible(std = "value")] + | ^^^^^^^^^^^^^ + +error: `cfg_accessible` path cannot accept arguments + --> $DIR/cfg_accessible-input-validation.rs:21:18 + | +LL | #[cfg_accessible(std(value))] + | ^^^^^^^^^^ + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs b/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs new file mode 100644 index 00000000000..8bc93fa3243 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-stuck.rs @@ -0,0 +1,9 @@ +#![feature(cfg_accessible)] + +#[cfg_accessible(Z)] //~ ERROR cannot determine whether the path is accessible or not +struct S; + +#[cfg_accessible(S)] //~ ERROR cannot determine whether the path is accessible or not +struct Z; + +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr b/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr new file mode 100644 index 00000000000..9641441a819 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-stuck.stderr @@ -0,0 +1,14 @@ +error: cannot determine whether the path is accessible or not + --> $DIR/cfg_accessible-stuck.rs:6:1 + | +LL | #[cfg_accessible(S)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: cannot determine whether the path is accessible or not + --> $DIR/cfg_accessible-stuck.rs:3:1 + | +LL | #[cfg_accessible(Z)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/conditional-compilation/cfg_accessible-unstable.rs b/src/test/ui/conditional-compilation/cfg_accessible-unstable.rs new file mode 100644 index 00000000000..e9247e67a2a --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-unstable.rs @@ -0,0 +1,2 @@ +#[cfg_accessible(std)] //~ ERROR use of unstable library feature 'cfg_accessible' +fn main() {} diff --git a/src/test/ui/conditional-compilation/cfg_accessible-unstable.stderr b/src/test/ui/conditional-compilation/cfg_accessible-unstable.stderr new file mode 100644 index 00000000000..2f55b9559c7 --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible-unstable.stderr @@ -0,0 +1,12 @@ +error[E0658]: use of unstable library feature 'cfg_accessible': `cfg_accessible` is not fully implemented + --> $DIR/cfg_accessible-unstable.rs:1:3 + | +LL | #[cfg_accessible(std)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #64797 for more information + = help: add `#![feature(cfg_accessible)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/conditional-compilation/cfg_accessible.rs b/src/test/ui/conditional-compilation/cfg_accessible.rs new file mode 100644 index 00000000000..07b0be5b1ae --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible.rs @@ -0,0 +1,43 @@ +#![feature(cfg_accessible)] + +mod m { + pub struct ExistingPublic; + struct ExistingPrivate; +} + +#[cfg_accessible(m::ExistingPublic)] +struct ExistingPublic; + +// FIXME: Not implemented yet. +#[cfg_accessible(m::ExistingPrivate)] //~ ERROR not sure whether the path is accessible or not +struct ExistingPrivate; + +// FIXME: Not implemented yet. +#[cfg_accessible(m::NonExistent)] //~ ERROR not sure whether the path is accessible or not +struct ExistingPrivate; + +#[cfg_accessible(n::AccessibleExpanded)] // OK, `cfg_accessible` can wait and retry. +struct AccessibleExpanded; + +macro_rules! generate_accessible_expanded { + () => { + mod n { + pub struct AccessibleExpanded; + } + }; +} + +generate_accessible_expanded!(); + +struct S { + field: u8, +} + +// FIXME: Not implemented yet. +#[cfg_accessible(S::field)] //~ ERROR not sure whether the path is accessible or not +struct Field; + +fn main() { + ExistingPublic; + AccessibleExpanded; +} diff --git a/src/test/ui/conditional-compilation/cfg_accessible.stderr b/src/test/ui/conditional-compilation/cfg_accessible.stderr new file mode 100644 index 00000000000..167765cd66e --- /dev/null +++ b/src/test/ui/conditional-compilation/cfg_accessible.stderr @@ -0,0 +1,38 @@ +error: not sure whether the path is accessible or not + --> $DIR/cfg_accessible.rs:12:18 + | +LL | #[cfg_accessible(m::ExistingPrivate)] + | ^^^^^^^^^^^^^^^^^^ + | +note: `cfg_accessible` is not fully implemented + --> $DIR/cfg_accessible.rs:12:18 + | +LL | #[cfg_accessible(m::ExistingPrivate)] + | ^^^^^^^^^^^^^^^^^^ + +error: not sure whether the path is accessible or not + --> $DIR/cfg_accessible.rs:16:18 + | +LL | #[cfg_accessible(m::NonExistent)] + | ^^^^^^^^^^^^^^ + | +note: `cfg_accessible` is not fully implemented + --> $DIR/cfg_accessible.rs:16:18 + | +LL | #[cfg_accessible(m::NonExistent)] + | ^^^^^^^^^^^^^^ + +error: not sure whether the path is accessible or not + --> $DIR/cfg_accessible.rs:37:18 + | +LL | #[cfg_accessible(S::field)] + | ^^^^^^^^ + | +note: `cfg_accessible` is not fully implemented + --> $DIR/cfg_accessible.rs:37:18 + | +LL | #[cfg_accessible(S::field)] + | ^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/conflicting-repr-hints.stderr b/src/test/ui/conflicting-repr-hints.stderr index 43b76bf6497..0b78532c737 100644 --- a/src/test/ui/conflicting-repr-hints.stderr +++ b/src/test/ui/conflicting-repr-hints.stderr @@ -76,5 +76,5 @@ LL | | } error: aborting due to 10 previous errors -Some errors have detailed explanations: E0566, E0587. +Some errors have detailed explanations: E0566, E0587, E0634. For more information about an error, try `rustc --explain E0566`. diff --git a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr index 781a179624e..c03377d74e9 100644 --- a/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr +++ b/src/test/ui/const-generics/array-impls/core-traits-no-impls-length-33.stderr @@ -23,8 +23,6 @@ LL | [0_usize; 33] == [1_usize; 33] | ------------- ^^ ------------- [usize; 33] | | | [usize; 33] - | - = note: an implementation of `std::cmp::PartialEq` might be missing for `[usize; 33]` error[E0369]: binary operation `<` cannot be applied to type `[usize; 33]` --> $DIR/core-traits-no-impls-length-33.rs:19:19 @@ -33,8 +31,6 @@ LL | [0_usize; 33] < [1_usize; 33] | ------------- ^ ------------- [usize; 33] | | | [usize; 33] - | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `[usize; 33]` error[E0277]: the trait bound `&[usize; 33]: std::iter::IntoIterator` is not satisfied --> $DIR/core-traits-no-impls-length-33.rs:24:14 diff --git a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr index 4869f483634..b39a160b529 100644 --- a/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr +++ b/src/test/ui/const-generics/array-impls/into-iter-no-impls-length-33.stderr @@ -1,8 +1,8 @@ error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/into-iter-no-impls-length-33.rs:12:5 + --> $DIR/into-iter-no-impls-length-33.rs:12:19 | LL | IntoIter::new([0i32; 33]) - | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` | = note: required by `std::array::IntoIter::::new` @@ -19,10 +19,10 @@ LL | IntoIter::new([0i32; 33]) = note: the return type of a function must have a statically known size error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/into-iter-no-impls-length-33.rs:18:5 + --> $DIR/into-iter-no-impls-length-33.rs:18:19 | LL | IntoIter::new([0i32; 33]) - | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` | = note: required by `std::array::IntoIter::::new` @@ -39,10 +39,10 @@ LL | IntoIter::new([0i32; 33]) = note: the return type of a function must have a statically known size error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/into-iter-no-impls-length-33.rs:24:5 + --> $DIR/into-iter-no-impls-length-33.rs:24:19 | LL | IntoIter::new([0i32; 33]) - | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` | = note: required by `std::array::IntoIter::::new` @@ -59,10 +59,10 @@ LL | IntoIter::new([0i32; 33]) = note: the return type of a function must have a statically known size error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/into-iter-no-impls-length-33.rs:30:5 + --> $DIR/into-iter-no-impls-length-33.rs:30:19 | LL | IntoIter::new([0i32; 33]) - | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` | = note: required by `std::array::IntoIter::::new` @@ -79,10 +79,10 @@ LL | IntoIter::new([0i32; 33]) = note: the return type of a function must have a statically known size error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/into-iter-no-impls-length-33.rs:36:5 + --> $DIR/into-iter-no-impls-length-33.rs:36:19 | LL | IntoIter::new([0i32; 33]) - | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` | = note: required by `std::array::IntoIter::::new` @@ -99,10 +99,10 @@ LL | IntoIter::new([0i32; 33]) = note: the return type of a function must have a statically known size error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/into-iter-no-impls-length-33.rs:42:5 + --> $DIR/into-iter-no-impls-length-33.rs:42:19 | LL | IntoIter::new([0i32; 33]) - | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` | = note: required by `std::array::IntoIter::::new` @@ -119,10 +119,10 @@ LL | IntoIter::new([0i32; 33]) = note: the return type of a function must have a statically known size error[E0277]: arrays only have std trait implementations for lengths 0..=32 - --> $DIR/into-iter-no-impls-length-33.rs:48:5 + --> $DIR/into-iter-no-impls-length-33.rs:48:19 | LL | IntoIter::new([0i32; 33]) - | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` + | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]` | = note: required by `std::array::IntoIter::::new` diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr index 8379cbd4908..c1d7022d56b 100644 --- a/src/test/ui/const-generics/cannot-infer-const-args.stderr +++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr @@ -10,7 +10,7 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:9:5 | LL | foo(); - | ^^^ cannot infer type for fn item `fn() -> usize {foo::<_: usize>}` + | ^^^ cannot infer type for fn item `fn() -> usize {foo::<{_: usize}>}` error: aborting due to previous error diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.rs b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs new file mode 100644 index 00000000000..f024eb6a957 --- /dev/null +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs @@ -0,0 +1,10 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +type Array = [T; N]; + +fn foo() -> Array { //~ ERROR constant provided when a type was expected + unimplemented!() +} + +fn main() {} diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr new file mode 100644 index 00000000000..150a6011c2c --- /dev/null +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr @@ -0,0 +1,19 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-arg-type-arg-misordered.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0747]: constant provided when a type was expected + --> $DIR/const-arg-type-arg-misordered.rs:6:35 + | +LL | fn foo() -> Array { + | ^ + | + = note: type arguments must be provided before constant arguments + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/const-generics/const-generic-type_name.rs b/src/test/ui/const-generics/const-generic-type_name.rs index 28586426b44..469843d6aae 100644 --- a/src/test/ui/const-generics/const-generic-type_name.rs +++ b/src/test/ui/const-generics/const-generic-type_name.rs @@ -7,5 +7,5 @@ struct S; fn main() { - assert_eq!(std::any::type_name::>(), "const_generic_type_name::S<3usize>"); + assert_eq!(std::any::type_name::>(), "const_generic_type_name::S<3>"); } diff --git a/src/test/ui/const-generics/const-param-after-const-literal-arg.rs b/src/test/ui/const-generics/const-param-after-const-literal-arg.rs new file mode 100644 index 00000000000..19c4120eb2f --- /dev/null +++ b/src/test/ui/const-generics/const-param-after-const-literal-arg.rs @@ -0,0 +1,10 @@ +// check-pass + +#![allow(incomplete_features)] +#![feature(const_generics)] + +struct Foo; + +impl Foo<1, A> {} // ok + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs index 5bdbfd8ff1f..756e961ce91 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.rs +++ b/src/test/ui/const-generics/const-param-before-other-params.rs @@ -1,3 +1,4 @@ +#![allow(incomplete_features)] #![feature(const_generics)] fn bar(_: &'a ()) { diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr index 87622f7e500..9b18b8c79ed 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.stderr +++ b/src/test/ui/const-generics/const-param-before-other-params.stderr @@ -1,11 +1,11 @@ error: lifetime parameters must be declared prior to const parameters - --> $DIR/const-param-before-other-params.rs:3:21 + --> $DIR/const-param-before-other-params.rs:4:21 | LL | fn bar(_: &'a ()) { | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>` error: type parameters must be declared prior to const parameters - --> $DIR/const-param-before-other-params.rs:7:21 + --> $DIR/const-param-before-other-params.rs:8:21 | LL | fn foo(_: &T) { | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr index 44eab8baa40..05d2dff8e98 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -10,12 +10,12 @@ error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:16:31 | LL | let _: Checked = Checked::; - | ---------------- ^^^^^^^^^^^^^^^^^^ expected `not_one`, found `not_two` + | ---------------- ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}` | | | expected due to this | - = note: expected struct `Checked` - found struct `Checked` + = note: expected struct `Checked<{not_one as fn(usize) -> bool}>` + found struct `Checked<{not_two as fn(usize) -> bool}>` error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:20:24 @@ -36,12 +36,12 @@ error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:25:40 | LL | let _: Checked<{generic::}> = Checked::<{generic::}>; - | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `generic::`, found `generic::` + | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic:: as fn(usize) -> bool}`, found `{generic:: as fn(usize) -> bool}` | | | expected due to this | - = note: expected struct `Checked>` - found struct `Checked>` + = note: expected struct `Checked<{generic:: as fn(usize) -> bool}>` + found struct `Checked<{generic:: as fn(usize) -> bool}>` error: aborting due to 4 previous errors diff --git a/src/test/ui/const-generics/issues/issue-65675.rs b/src/test/ui/const-generics/issues/issue-62456.rs similarity index 51% rename from src/test/ui/const-generics/issues/issue-65675.rs rename to src/test/ui/const-generics/issues/issue-62456.rs index 3ca527313f9..c5e6fe9104b 100644 --- a/src/test/ui/const-generics/issues/issue-65675.rs +++ b/src/test/ui/const-generics/issues/issue-62456.rs @@ -1,10 +1,9 @@ -// run-pass -// compile-flags: -Z chalk - #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -pub struct Foo([T; N]); -impl Foo {} +fn foo() { + let _ = [0u64; N + 1]; + //~^ ERROR array lengths can't depend on generic parameters +} fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr new file mode 100644 index 00000000000..9cdccf8407c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62456.stderr @@ -0,0 +1,16 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-62456.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error: array lengths can't depend on generic parameters + --> $DIR/issue-62456.rs:5:20 + | +LL | let _ = [0u64; N + 1]; + | ^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs new file mode 100644 index 00000000000..74ed3d354fc --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -0,0 +1,25 @@ +// Regression test for #62504 + +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait HasSize { + const SIZE: usize; +} + +impl HasSize for ArrayHolder<{ X }> { + const SIZE: usize = X; +} + +struct ArrayHolder([u32; X]); + +impl ArrayHolder<{ X }> { + pub const fn new() -> Self { + ArrayHolder([0; Self::SIZE]) + //~^ ERROR: array lengths can't depend on generic parameters + } +} + +fn main() { + let mut array = ArrayHolder::new(); +} diff --git a/src/test/ui/const-generics/issues/issue-62504.stderr b/src/test/ui/const-generics/issues/issue-62504.stderr new file mode 100644 index 00000000000..c2a752ec171 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62504.stderr @@ -0,0 +1,8 @@ +error: array lengths can't depend on generic parameters + --> $DIR/issue-62504.rs:18:25 + | +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-65675.stderr b/src/test/ui/const-generics/issues/issue-65675.stderr deleted file mode 100644 index 60b388e6278..00000000000 --- a/src/test/ui/const-generics/issues/issue-65675.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: the feature `const_generics` is incomplete and may cause the compiler to crash - --> $DIR/issue-65675.rs:4:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs new file mode 100644 index 00000000000..79c5ac9dd18 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67739.rs @@ -0,0 +1,18 @@ +// Regression test for #67739 + +#![allow(incomplete_features)] +#![feature(const_generics)] + +use std::mem; + +pub trait Trait { + type Associated: Sized; + + fn associated_size(&self) -> usize { + [0u8; mem::size_of::()]; + //~^ ERROR: array lengths can't depend on generic parameters + 0 + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-67739.stderr b/src/test/ui/const-generics/issues/issue-67739.stderr new file mode 100644 index 00000000000..a31b556c086 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67739.stderr @@ -0,0 +1,8 @@ +error: array lengths can't depend on generic parameters + --> $DIR/issue-67739.rs:12:15 + | +LL | [0u8; mem::size_of::()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/raw-ptr-const-param.rs b/src/test/ui/const-generics/raw-ptr-const-param.rs index f69c37fbb8f..f0349f46962 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.rs +++ b/src/test/ui/const-generics/raw-ptr-const-param.rs @@ -4,6 +4,6 @@ struct Const; fn main() { - let _: Const<{15 as *const _}> = Const::<{10 as *const _}>; //~ mismatched types - let _: Const<{10 as *const _}> = Const::<{10 as *const _}>; + let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; //~ mismatched types + let _: Const<{ 10 as *const _ }> = Const::<{ 10 as *const _ }>; } diff --git a/src/test/ui/const-generics/raw-ptr-const-param.stderr b/src/test/ui/const-generics/raw-ptr-const-param.stderr index 9cd39b61dc9..d9794f60a19 100644 --- a/src/test/ui/const-generics/raw-ptr-const-param.stderr +++ b/src/test/ui/const-generics/raw-ptr-const-param.stderr @@ -7,15 +7,15 @@ LL | #![feature(const_generics, const_compare_raw_pointers)] = note: `#[warn(incomplete_features)]` on by default error[E0308]: mismatched types - --> $DIR/raw-ptr-const-param.rs:7:38 + --> $DIR/raw-ptr-const-param.rs:7:40 | -LL | let _: Const<{15 as *const _}> = Const::<{10 as *const _}>; - | ----------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{pointer}`, found `{pointer}` +LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; + | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}` | | | expected due to this | - = note: expected struct `Const<{pointer}>` - found struct `Const<{pointer}>` + = note: expected struct `Const<{0xf as *const u32}>` + found struct `Const<{0xa as *const u32}>` error: aborting due to previous error diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs index af63d1f75a7..492afa9372c 100644 --- a/src/test/ui/consts/array-literal-index-oob.rs +++ b/src/test/ui/consts/array-literal-index-oob.rs @@ -1,11 +1,11 @@ // build-pass // ignore-pass (emit codegen-time warnings and verify that they are indeed warnings and not errors) -#![warn(const_err)] +#![warn(const_err, unconditional_panic)] fn main() { &{ [1, 2, 3][4] }; - //~^ WARN index out of bounds + //~^ WARN operation will panic //~| WARN reaching this expression at runtime will panic or abort //~| WARN erroneous constant used [const_err] } diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr index 59e11697015..6e0e7fedb7b 100644 --- a/src/test/ui/consts/array-literal-index-oob.stderr +++ b/src/test/ui/consts/array-literal-index-oob.stderr @@ -1,14 +1,14 @@ -warning: index out of bounds: the len is 3 but the index is 4 +warning: this operation will panic at runtime --> $DIR/array-literal-index-oob.rs:7:8 | LL | &{ [1, 2, 3][4] }; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 4 | note: the lint level is defined here - --> $DIR/array-literal-index-oob.rs:4:9 + --> $DIR/array-literal-index-oob.rs:4:20 | -LL | #![warn(const_err)] - | ^^^^^^^^^ +LL | #![warn(const_err, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ warning: reaching this expression at runtime will panic or abort --> $DIR/array-literal-index-oob.rs:7:8 @@ -17,6 +17,12 @@ LL | &{ [1, 2, 3][4] }; | ---^^^^^^^^^^^^-- | | | indexing out of bounds: the len is 3 but the index is 4 + | +note: the lint level is defined here + --> $DIR/array-literal-index-oob.rs:4:9 + | +LL | #![warn(const_err, unconditional_panic)] + | ^^^^^^^^^ warning: erroneous constant used --> $DIR/array-literal-index-oob.rs:7:5 diff --git a/src/test/ui/consts/const-err.rs b/src/test/ui/consts/const-err.rs index b204f705a96..d1c5f4f3f32 100644 --- a/src/test/ui/consts/const-err.rs +++ b/src/test/ui/consts/const-err.rs @@ -1,7 +1,7 @@ // build-fail // compile-flags: -Zforce-overflow-checks=on -#![allow(exceeding_bitshifts)] +#![allow(arithmetic_overflow)] #![warn(const_err)] fn black_box(_: T) { diff --git a/src/test/ui/consts/const-err2.stderr b/src/test/ui/consts/const-err2.noopt.stderr similarity index 50% rename from src/test/ui/consts/const-err2.stderr rename to src/test/ui/consts/const-err2.noopt.stderr index f135bf0b06c..5aeeec4bd14 100644 --- a/src/test/ui/consts/const-err2.stderr +++ b/src/test/ui/consts/const-err2.noopt.stderr @@ -1,50 +1,48 @@ -error: this expression will panic at runtime - --> $DIR/const-err2.rs:18:13 +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:19:13 | LL | let a = -std::i8::MIN; | ^^^^^^^^^^^^^ attempt to negate with overflow | -note: the lint level is defined here - --> $DIR/const-err2.rs:11:9 - | -LL | #![deny(const_err)] - | ^^^^^^^^^ + = note: `#[deny(arithmetic_overflow)]` on by default -error: this expression will panic at runtime - --> $DIR/const-err2.rs:20:18 +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:21:18 | LL | let a_i128 = -std::i128::MIN; | ^^^^^^^^^^^^^^^ attempt to negate with overflow -error: this expression will panic at runtime - --> $DIR/const-err2.rs:22:13 +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:23:13 | LL | let b = 200u8 + 200u8 + 200u8; | ^^^^^^^^^^^^^ attempt to add with overflow -error: this expression will panic at runtime - --> $DIR/const-err2.rs:24:18 +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:25:18 | LL | let b_i128 = std::i128::MIN - std::i128::MAX; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow -error: this expression will panic at runtime - --> $DIR/const-err2.rs:26:13 +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:27:13 | LL | let c = 200u8 * 4; | ^^^^^^^^^ attempt to multiply with overflow -error: this expression will panic at runtime - --> $DIR/const-err2.rs:28:13 +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:29:13 | LL | let d = 42u8 - (42u8 + 1); | ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow -error: index out of bounds: the len is 1 but the index is 1 - --> $DIR/const-err2.rs:30:14 +error: this operation will panic at runtime + --> $DIR/const-err2.rs:31:14 | LL | let _e = [5u8][1]; - | ^^^^^^^^ + | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | + = note: `#[deny(unconditional_panic)]` on by default error: aborting due to 7 previous errors diff --git a/src/test/ui/consts/const-err2.opt.stderr b/src/test/ui/consts/const-err2.opt.stderr new file mode 100644 index 00000000000..5aeeec4bd14 --- /dev/null +++ b/src/test/ui/consts/const-err2.opt.stderr @@ -0,0 +1,48 @@ +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:19:13 + | +LL | let a = -std::i8::MIN; + | ^^^^^^^^^^^^^ attempt to negate with overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:21:18 + | +LL | let a_i128 = -std::i128::MIN; + | ^^^^^^^^^^^^^^^ attempt to negate with overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:23:13 + | +LL | let b = 200u8 + 200u8 + 200u8; + | ^^^^^^^^^^^^^ attempt to add with overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:25:18 + | +LL | let b_i128 = std::i128::MIN - std::i128::MAX; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:27:13 + | +LL | let c = 200u8 * 4; + | ^^^^^^^^^ attempt to multiply with overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:29:13 + | +LL | let d = 42u8 - (42u8 + 1); + | ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow + +error: this operation will panic at runtime + --> $DIR/const-err2.rs:31:14 + | +LL | let _e = [5u8][1]; + | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr new file mode 100644 index 00000000000..5aeeec4bd14 --- /dev/null +++ b/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr @@ -0,0 +1,48 @@ +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:19:13 + | +LL | let a = -std::i8::MIN; + | ^^^^^^^^^^^^^ attempt to negate with overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:21:18 + | +LL | let a_i128 = -std::i128::MIN; + | ^^^^^^^^^^^^^^^ attempt to negate with overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:23:13 + | +LL | let b = 200u8 + 200u8 + 200u8; + | ^^^^^^^^^^^^^ attempt to add with overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:25:18 + | +LL | let b_i128 = std::i128::MIN - std::i128::MAX; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:27:13 + | +LL | let c = 200u8 * 4; + | ^^^^^^^^^ attempt to multiply with overflow + +error: this arithmetic operation will overflow + --> $DIR/const-err2.rs:29:13 + | +LL | let d = 42u8 - (42u8 + 1); + | ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow + +error: this operation will panic at runtime + --> $DIR/const-err2.rs:31:14 + | +LL | let _e = [5u8][1]; + | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs index 7c5aaedda35..2c6a987180b 100644 --- a/src/test/ui/consts/const-err2.rs +++ b/src/test/ui/consts/const-err2.rs @@ -2,13 +2,14 @@ // optimized compilation and unoptimized compilation and thus would // lead to different lints being emitted +// revisions: noopt opt opt_with_overflow_checks +//[noopt]compile-flags: -C opt-level=0 +//[opt]compile-flags: -O +//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O + // build-fail -// compile-flags: -O #![feature(rustc_attrs)] -#![allow(exceeding_bitshifts)] - -#![deny(const_err)] fn black_box(_: T) { unimplemented!() @@ -16,19 +17,19 @@ fn black_box(_: T) { fn main() { let a = -std::i8::MIN; - //~^ ERROR const_err + //~^ ERROR arithmetic operation will overflow let a_i128 = -std::i128::MIN; - //~^ ERROR const_err + //~^ ERROR arithmetic operation will overflow let b = 200u8 + 200u8 + 200u8; - //~^ ERROR const_err + //~^ ERROR arithmetic operation will overflow let b_i128 = std::i128::MIN - std::i128::MAX; - //~^ ERROR const_err + //~^ ERROR arithmetic operation will overflow let c = 200u8 * 4; - //~^ ERROR const_err + //~^ ERROR arithmetic operation will overflow let d = 42u8 - (42u8 + 1); - //~^ ERROR const_err + //~^ ERROR arithmetic operation will overflow let _e = [5u8][1]; - //~^ ERROR const_err + //~^ ERROR operation will panic black_box(a); black_box(a_i128); black_box(b); diff --git a/src/test/ui/consts/const-err3.rs b/src/test/ui/consts/const-err3.rs deleted file mode 100644 index 43aba4a8b01..00000000000 --- a/src/test/ui/consts/const-err3.rs +++ /dev/null @@ -1,38 +0,0 @@ -// needed because negating int::MIN will behave differently between -// optimized compilation and unoptimized compilation and thus would -// lead to different lints being emitted - -// build-fail -// compile-flags: -C overflow-checks=on -O - -#![feature(rustc_attrs)] -#![allow(exceeding_bitshifts)] - -#![deny(const_err)] - -fn black_box(_: T) { - unimplemented!() -} - -fn main() { - let a = -std::i8::MIN; - //~^ ERROR const_err - let a_i128 = -std::i128::MIN; - //~^ ERROR const_err - let b = 200u8 + 200u8 + 200u8; - //~^ ERROR const_err - let b_i128 = std::i128::MIN - std::i128::MAX; - //~^ ERROR const_err - let c = 200u8 * 4; - //~^ ERROR const_err - let d = 42u8 - (42u8 + 1); - //~^ ERROR const_err - let _e = [5u8][1]; - //~^ ERROR const_err - black_box(a); - black_box(a_i128); - black_box(b); - black_box(b_i128); - black_box(c); - black_box(d); -} diff --git a/src/test/ui/consts/const-err3.stderr b/src/test/ui/consts/const-err3.stderr deleted file mode 100644 index 05f64b87fcc..00000000000 --- a/src/test/ui/consts/const-err3.stderr +++ /dev/null @@ -1,50 +0,0 @@ -error: attempt to negate with overflow - --> $DIR/const-err3.rs:18:13 - | -LL | let a = -std::i8::MIN; - | ^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/const-err3.rs:11:9 - | -LL | #![deny(const_err)] - | ^^^^^^^^^ - -error: attempt to negate with overflow - --> $DIR/const-err3.rs:20:18 - | -LL | let a_i128 = -std::i128::MIN; - | ^^^^^^^^^^^^^^^ - -error: attempt to add with overflow - --> $DIR/const-err3.rs:22:13 - | -LL | let b = 200u8 + 200u8 + 200u8; - | ^^^^^^^^^^^^^ - -error: attempt to subtract with overflow - --> $DIR/const-err3.rs:24:18 - | -LL | let b_i128 = std::i128::MIN - std::i128::MAX; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: attempt to multiply with overflow - --> $DIR/const-err3.rs:26:13 - | -LL | let c = 200u8 * 4; - | ^^^^^^^^^ - -error: attempt to subtract with overflow - --> $DIR/const-err3.rs:28:13 - | -LL | let d = 42u8 - (42u8 + 1); - | ^^^^^^^^^^^^^^^^^ - -error: index out of bounds: the len is 1 but the index is 1 - --> $DIR/const-err3.rs:30:14 - | -LL | let _e = [5u8][1]; - | ^^^^^^^^ - -error: aborting due to 7 previous errors - diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr index e0df787f80a..305f259eac2 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr @@ -12,7 +12,7 @@ error: any use of this value will cause an error LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes | = note: `#[deny(const_err)]` on by default @@ -22,7 +22,7 @@ error: any use of this value will cause an error LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:34:45 @@ -30,7 +30,7 @@ error: any use of this value will cause an error LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:37:5 @@ -54,7 +54,7 @@ error: any use of this value will cause an error LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:46:45 @@ -62,7 +62,7 @@ error: any use of this value will cause an error LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:49:45 @@ -70,7 +70,7 @@ error: any use of this value will cause an error LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:52:5 @@ -94,7 +94,7 @@ error: any use of this value will cause an error LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:61:5 @@ -110,7 +110,7 @@ error: any use of this value will cause an error LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:67:47 @@ -118,7 +118,7 @@ error: any use of this value will cause an error LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:70:39 @@ -126,7 +126,7 @@ error: any use of this value will cause an error LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:73:41 @@ -134,7 +134,7 @@ error: any use of this value will cause an error LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:76:41 @@ -142,7 +142,7 @@ error: any use of this value will cause an error LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:79:5 @@ -158,7 +158,7 @@ error: any use of this value will cause an error LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:85:39 @@ -166,7 +166,7 @@ error: any use of this value will cause an error LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:88:41 @@ -174,7 +174,7 @@ error: any use of this value will cause an error LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:91:41 @@ -182,7 +182,7 @@ error: any use of this value will cause an error LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:94:5 @@ -198,7 +198,7 @@ error: any use of this value will cause an error LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:100:41 @@ -206,7 +206,7 @@ error: any use of this value will cause an error LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:103:5 @@ -222,7 +222,7 @@ error: any use of this value will cause an error LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: any use of this value will cause an error --> $DIR/const-pointer-values-in-various-types.rs:109:43 @@ -230,7 +230,7 @@ error: any use of this value will cause an error LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | a raw memory access tried to access part of a pointer value as raw bytes + | unable to turn pointer into raw bytes error: aborting due to 29 previous errors diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_main.rs b/src/test/ui/consts/const-eval/const_panic_libcore_main.rs index 9afcdf77610..6b86feb5921 100644 --- a/src/test/ui/consts/const-eval/const_panic_libcore_main.rs +++ b/src/test/ui/consts/const-eval/const_panic_libcore_main.rs @@ -17,8 +17,6 @@ const X: () = unimplemented!(); #[lang = "eh_personality"] fn eh() {} -#[lang = "eh_unwind_resume"] -fn eh_unwind_resume() {} #[panic_handler] fn panic(_info: &PanicInfo) -> ! { diff --git a/src/test/ui/consts/const-eval/const_prop_errors.rs b/src/test/ui/consts/const-eval/const_prop_errors.rs index 48cfea82bd6..f9a36d37943 100644 --- a/src/test/ui/consts/const-eval/const_prop_errors.rs +++ b/src/test/ui/consts/const-eval/const_prop_errors.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass pub trait Foo { fn foo(self) -> u32; diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr index 2cba833a748..cc40728e6b5 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr @@ -30,7 +30,7 @@ error: any use of this value will cause an error LL | const Z2: i32 = unsafe { *(42 as *const i32) }; | -------------------------^^^^^^^^^^^^^^^^^^^--- | | - | a memory access tried to interpret some bytes as a pointer + | unable to turn bytes into a pointer error: any use of this value will cause an error --> $DIR/const_raw_ptr_ops.rs:17:26 @@ -38,7 +38,7 @@ error: any use of this value will cause an error LL | const Z3: i32 = unsafe { *(44 as *const i32) }; | -------------------------^^^^^^^^^^^^^^^^^^^--- | | - | a memory access tried to interpret some bytes as a pointer + | unable to turn bytes into a pointer error: aborting due to 5 previous errors diff --git a/src/test/ui/consts/const-eval/const_signed_pat.rs b/src/test/ui/consts/const-eval/const_signed_pat.rs index d209e604486..c61239bb677 100644 --- a/src/test/ui/consts/const-eval/const_signed_pat.rs +++ b/src/test/ui/consts/const-eval/const_signed_pat.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass fn main() { const MIN: i8 = -5; diff --git a/src/test/ui/consts/const-eval/dangling.rs b/src/test/ui/consts/const-eval/dangling.rs index b5d72d46f28..c6b8e8eb611 100644 --- a/src/test/ui/consts/const-eval/dangling.rs +++ b/src/test/ui/consts/const-eval/dangling.rs @@ -6,7 +6,7 @@ use std::{mem, usize}; const TEST: () = { unsafe { //~ NOTE let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); let _val = &*slice; //~ ERROR: any use of this value will cause an error - //~^ NOTE: total size is bigger than largest supported object + //~^ NOTE: slice is bigger than largest supported object //~^^ on by default } }; diff --git a/src/test/ui/consts/const-eval/dangling.stderr b/src/test/ui/consts/const-eval/dangling.stderr index 286de080097..b9ddc93b03b 100644 --- a/src/test/ui/consts/const-eval/dangling.stderr +++ b/src/test/ui/consts/const-eval/dangling.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | / const TEST: () = { unsafe { LL | | let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); LL | | let _val = &*slice; - | | ^^^^^^^ invalid slice: total size is bigger than largest supported object + | | ^^^^^^^ invalid metadata in wide pointer: slice is bigger than largest supported object LL | | LL | | LL | | } }; diff --git a/src/test/ui/consts/const-eval/double_check.rs b/src/test/ui/consts/const-eval/double_check.rs index ff2fff7fb79..f156d259abb 100644 --- a/src/test/ui/consts/const-eval/double_check.rs +++ b/src/test/ui/consts/const-eval/double_check.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass enum Foo { A = 5, diff --git a/src/test/ui/consts/const-eval/double_promotion.rs b/src/test/ui/consts/const-eval/double_promotion.rs index a9a3f071bf8..48f4426d9cf 100644 --- a/src/test/ui/consts/const-eval/double_promotion.rs +++ b/src/test/ui/consts/const-eval/double_promotion.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass #![feature(const_fn, rustc_attrs)] diff --git a/src/test/ui/consts/const-eval/duration_conversion.rs b/src/test/ui/consts/const-eval/duration_conversion.rs index 029d4e5e373..87b12937dd4 100644 --- a/src/test/ui/consts/const-eval/duration_conversion.rs +++ b/src/test/ui/consts/const-eval/duration_conversion.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass use std::time::Duration; diff --git a/src/test/ui/consts/const-eval/extern_fat_pointer.rs b/src/test/ui/consts/const-eval/extern_fat_pointer.rs index e2b3bc83c3f..f210d1a0a90 100644 --- a/src/test/ui/consts/const-eval/extern_fat_pointer.rs +++ b/src/test/ui/consts/const-eval/extern_fat_pointer.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass #![feature(extern_types)] diff --git a/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs b/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs index ce0e11f29f4..4444cdfcda9 100644 --- a/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs +++ b/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass pub trait Nullable { const NULL: Self; diff --git a/src/test/ui/consts/const-eval/ice-packed.rs b/src/test/ui/consts/const-eval/ice-packed.rs index 250bf954e9a..4758a5a9d56 100644 --- a/src/test/ui/consts/const-eval/ice-packed.rs +++ b/src/test/ui/consts/const-eval/ice-packed.rs @@ -1,4 +1,7 @@ -// build-pass (FIXME(62277): could be check-pass?) +// Regression test for #50356: Compiler panic when using repr(packed) +// associated constant in a match arm + +// check-pass #[derive(Copy, Clone, PartialEq, Eq)] #[repr(packed)] pub struct Num(u64); diff --git a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.rs b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.rs index 6d6bb94d4df..608e6e112a1 100644 --- a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.rs +++ b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.rs @@ -2,5 +2,5 @@ fn main() { let array = [std::env::args().len()]; - array[1]; //~ ERROR index out of bounds + array[1]; //~ ERROR operation will panic } diff --git a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr index 9519ccd3c24..4188efd021d 100644 --- a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr +++ b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr @@ -1,10 +1,10 @@ -error: index out of bounds: the len is 1 but the index is 1 +error: this operation will panic at runtime --> $DIR/index_out_of_bounds_propagated.rs:5:5 | LL | array[1]; - | ^^^^^^^^ + | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 | - = note: `#[deny(const_err)]` on by default + = note: `#[deny(unconditional_panic)]` on by default error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/issue-47971.rs b/src/test/ui/consts/const-eval/issue-47971.rs index 9de150bd052..b98e76031d4 100644 --- a/src/test/ui/consts/const-eval/issue-47971.rs +++ b/src/test/ui/consts/const-eval/issue-47971.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass struct S(pub &'static u32, pub u32); diff --git a/src/test/ui/consts/const-eval/issue-49296.stderr b/src/test/ui/consts/const-eval/issue-49296.stderr index 48809e0ae64..798f130a4ba 100644 --- a/src/test/ui/consts/const-eval/issue-49296.stderr +++ b/src/test/ui/consts/const-eval/issue-49296.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const X: u64 = *wat(42); | ---------------^^^^^^^^- | | - | dangling pointer was dereferenced + | pointer to alloc2 was dereferenced after this allocation got freed | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/const-eval/issue-50706.rs b/src/test/ui/consts/const-eval/issue-50706.rs index bf69bc28da4..a13c27f2e78 100644 --- a/src/test/ui/consts/const-eval/issue-50706.rs +++ b/src/test/ui/consts/const-eval/issue-50706.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass pub struct Stats; diff --git a/src/test/ui/consts/const-eval/issue-51300.rs b/src/test/ui/consts/const-eval/issue-51300.rs index 4753bf0f7b1..8e68e8c9117 100644 --- a/src/test/ui/consts/const-eval/issue-51300.rs +++ b/src/test/ui/consts/const-eval/issue-51300.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // https://github.com/rust-lang/rust/issues/51300 #[derive(PartialEq, Eq, Clone, Copy)] diff --git a/src/test/ui/consts/const-eval/issue-53157.rs b/src/test/ui/consts/const-eval/issue-53157.rs index ac0940b33e4..850338625bc 100644 --- a/src/test/ui/consts/const-eval/issue-53157.rs +++ b/src/test/ui/consts/const-eval/issue-53157.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass macro_rules! m { () => {{ diff --git a/src/test/ui/consts/const-eval/issue-53401.rs b/src/test/ui/consts/const-eval/issue-53401.rs index d300e0b5125..31c946c3cb7 100644 --- a/src/test/ui/consts/const-eval/issue-53401.rs +++ b/src/test/ui/consts/const-eval/issue-53401.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass pub const STATIC_TRAIT: &dyn Test = &(); diff --git a/src/test/ui/consts/const-eval/issue-55541.rs b/src/test/ui/consts/const-eval/issue-55541.rs index d04570c67ff..4c9e10d9cbe 100644 --- a/src/test/ui/consts/const-eval/issue-55541.rs +++ b/src/test/ui/consts/const-eval/issue-55541.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // Test that we can handle newtypes wrapping extern types diff --git a/src/test/ui/consts/const-eval/no_lint_for_statically_known_error.rs b/src/test/ui/consts/const-eval/no_lint_for_statically_known_error.rs index cea367528c9..910ca3c4bcb 100644 --- a/src/test/ui/consts/const-eval/no_lint_for_statically_known_error.rs +++ b/src/test/ui/consts/const-eval/no_lint_for_statically_known_error.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // if `X` were used instead of `x`, `X - 10` would result in a lint. // This file should never produce a lint, no matter how the const diff --git a/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs b/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs index ca75d65a39a..edda10e6e82 100644 --- a/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs +++ b/src/test/ui/consts/const-eval/promote_mutable_zst_mir_borrowck.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass pub fn main() { let y: &'static mut [u8; 0] = &mut []; diff --git a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr new file mode 100644 index 00000000000..94c1593240b --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr @@ -0,0 +1,78 @@ +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:12:20 + | +LL | println!("{}", 0u32 - 1); + | ^^^^^^^^ attempt to subtract with overflow + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:20 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:14:14 + | +LL | let _x = 0u32 - 1; + | ^^^^^^^^ attempt to subtract with overflow + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ attempt to divide by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:41 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ dividing by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:9 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^ + +warning: erroneous constant used + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:20:14 + | +LL | let _x = 1 / (1 - 1); + | ^^^^^^^^^^^ attempt to divide by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ dividing by zero + +warning: erroneous constant used + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:26:14 + | +LL | let _x = 1 / (false as u32); + | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero + diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr new file mode 100644 index 00000000000..034dea06568 --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr @@ -0,0 +1,72 @@ +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:14:14 + | +LL | let _x = 0u32 - 1; + | ^^^^^^^^ attempt to subtract with overflow + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:20 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ attempt to divide by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:41 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ dividing by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:9 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^ + +warning: erroneous constant used + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:20:14 + | +LL | let _x = 1 / (1 - 1); + | ^^^^^^^^^^^ attempt to divide by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ dividing by zero + +warning: erroneous constant used + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:26:14 + | +LL | let _x = 1 / (false as u32); + | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero + diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr new file mode 100644 index 00000000000..94c1593240b --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr @@ -0,0 +1,78 @@ +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:12:20 + | +LL | println!("{}", 0u32 - 1); + | ^^^^^^^^ attempt to subtract with overflow + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:20 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: this arithmetic operation will overflow + --> $DIR/promoted_errors.rs:14:14 + | +LL | let _x = 0u32 - 1; + | ^^^^^^^^ attempt to subtract with overflow + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ attempt to divide by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:41 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ dividing by zero + | +note: the lint level is defined here + --> $DIR/promoted_errors.rs:9:9 + | +LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] + | ^^^^^^^^^ + +warning: erroneous constant used + --> $DIR/promoted_errors.rs:16:20 + | +LL | println!("{}", 1 / (1 - 1)); + | ^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:20:14 + | +LL | let _x = 1 / (1 - 1); + | ^^^^^^^^^^^ attempt to divide by zero + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero + +warning: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ dividing by zero + +warning: erroneous constant used + --> $DIR/promoted_errors.rs:22:20 + | +LL | println!("{}", 1 / (false as u32)); + | ^^^^^^^^^^^^^^^^^^ referenced constant has errors + +warning: this operation will panic at runtime + --> $DIR/promoted_errors.rs:26:14 + | +LL | let _x = 1 / (false as u32); + | ^^^^^^^^^^^^^^^^^^ attempt to divide by zero + diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs index 22f863fb15a..3ab6ce28478 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.rs +++ b/src/test/ui/consts/const-eval/promoted_errors.rs @@ -1,23 +1,28 @@ +// revisions: noopt opt opt_with_overflow_checks +//[noopt]compile-flags: -C opt-level=0 +//[opt]compile-flags: -O +//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O + // build-pass // ignore-pass (emit codegen-time warnings and verify that they are indeed warnings and not errors) -// compile-flags: -O -#![warn(const_err)] +#![warn(const_err, arithmetic_overflow, unconditional_panic)] fn main() { println!("{}", 0u32 - 1); + //[opt_with_overflow_checks,noopt]~^ WARN [arithmetic_overflow] let _x = 0u32 - 1; - //~^ WARN const_err + //~^ WARN [arithmetic_overflow] println!("{}", 1 / (1 - 1)); - //~^ WARN attempt to divide by zero [const_err] - //~| WARN const_err + //~^ WARN [unconditional_panic] + //~| WARN panic or abort [const_err] //~| WARN erroneous constant used [const_err] let _x = 1 / (1 - 1); - //~^ WARN const_err + //~^ WARN [unconditional_panic] println!("{}", 1 / (false as u32)); - //~^ WARN attempt to divide by zero [const_err] - //~| WARN const_err + //~^ WARN [unconditional_panic] + //~| WARN panic or abort [const_err] //~| WARN erroneous constant used [const_err] let _x = 1 / (false as u32); - //~^ WARN const_err + //~^ WARN [unconditional_panic] } diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr deleted file mode 100644 index 08ae5c7a32b..00000000000 --- a/src/test/ui/consts/const-eval/promoted_errors.stderr +++ /dev/null @@ -1,60 +0,0 @@ -warning: this expression will panic at runtime - --> $DIR/promoted_errors.rs:9:14 - | -LL | let _x = 0u32 - 1; - | ^^^^^^^^ attempt to subtract with overflow - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:5:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - -warning: attempt to divide by zero - --> $DIR/promoted_errors.rs:11:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ - -warning: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:11:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ dividing by zero - -warning: erroneous constant used - --> $DIR/promoted_errors.rs:11:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ referenced constant has errors - -warning: attempt to divide by zero - --> $DIR/promoted_errors.rs:15:14 - | -LL | let _x = 1 / (1 - 1); - | ^^^^^^^^^^^ - -warning: attempt to divide by zero - --> $DIR/promoted_errors.rs:17:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ - -warning: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:17:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ dividing by zero - -warning: erroneous constant used - --> $DIR/promoted_errors.rs:17:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ referenced constant has errors - -warning: attempt to divide by zero - --> $DIR/promoted_errors.rs:21:14 - | -LL | let _x = 1 / (false as u32); - | ^^^^^^^^^^^^^^^^^^ - diff --git a/src/test/ui/consts/const-eval/promoted_errors2.rs b/src/test/ui/consts/const-eval/promoted_errors2.rs deleted file mode 100644 index 62c77f76d90..00000000000 --- a/src/test/ui/consts/const-eval/promoted_errors2.rs +++ /dev/null @@ -1,24 +0,0 @@ -// build-pass -// ignore-pass (emit codegen-time warnings and verify that they are indeed warnings and not errors) -// compile-flags: -C overflow-checks=on -O - -#![warn(const_err)] - -fn main() { - println!("{}", 0u32 - 1); - //~^ WARN attempt to subtract with overflow - let _x = 0u32 - 1; - //~^ WARN attempt to subtract with overflow - println!("{}", 1 / (1 - 1)); - //~^ WARN attempt to divide by zero [const_err] - //~| WARN const_err - //~| WARN erroneous constant used [const_err] - let _x = 1 / (1 - 1); - //~^ WARN const_err - println!("{}", 1 / (false as u32)); - //~^ WARN attempt to divide by zero [const_err] - //~| WARN const_err - //~| WARN erroneous constant used [const_err] - let _x = 1 / (false as u32); - //~^ WARN const_err -} diff --git a/src/test/ui/consts/const-eval/promoted_errors2.stderr b/src/test/ui/consts/const-eval/promoted_errors2.stderr deleted file mode 100644 index d1a9cb958e1..00000000000 --- a/src/test/ui/consts/const-eval/promoted_errors2.stderr +++ /dev/null @@ -1,66 +0,0 @@ -warning: attempt to subtract with overflow - --> $DIR/promoted_errors2.rs:8:20 - | -LL | println!("{}", 0u32 - 1); - | ^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/promoted_errors2.rs:5:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - -warning: attempt to subtract with overflow - --> $DIR/promoted_errors2.rs:10:14 - | -LL | let _x = 0u32 - 1; - | ^^^^^^^^ - -warning: attempt to divide by zero - --> $DIR/promoted_errors2.rs:12:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ - -warning: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors2.rs:12:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ dividing by zero - -warning: erroneous constant used - --> $DIR/promoted_errors2.rs:12:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ referenced constant has errors - -warning: attempt to divide by zero - --> $DIR/promoted_errors2.rs:16:14 - | -LL | let _x = 1 / (1 - 1); - | ^^^^^^^^^^^ - -warning: attempt to divide by zero - --> $DIR/promoted_errors2.rs:18:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ - -warning: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors2.rs:18:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ dividing by zero - -warning: erroneous constant used - --> $DIR/promoted_errors2.rs:18:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ referenced constant has errors - -warning: attempt to divide by zero - --> $DIR/promoted_errors2.rs:22:14 - | -LL | let _x = 1 / (false as u32); - | ^^^^^^^^^^^^^^^^^^ - diff --git a/src/test/ui/consts/const-eval/pub_const_err.rs b/src/test/ui/consts/const-eval/pub_const_err.rs index 4ff140fee7a..ad165d40a76 100644 --- a/src/test/ui/consts/const-eval/pub_const_err.rs +++ b/src/test/ui/consts/const-eval/pub_const_err.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass #![warn(const_err)] #![crate_type = "lib"] diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.rs b/src/test/ui/consts/const-eval/pub_const_err_bin.rs index 7f1586336e7..078e4c896df 100644 --- a/src/test/ui/consts/const-eval/pub_const_err_bin.rs +++ b/src/test/ui/consts/const-eval/pub_const_err_bin.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass #![warn(const_err)] pub const Z: u32 = 0 - 1; diff --git a/src/test/ui/consts/const-eval/simple_with_undef.rs b/src/test/ui/consts/const-eval/simple_with_undef.rs index 8a9f3fe974d..1a416dd460d 100644 --- a/src/test/ui/consts/const-eval/simple_with_undef.rs +++ b/src/test/ui/consts/const-eval/simple_with_undef.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass const PARSE_BOOL: Option<&'static str> = None; static FOO: (Option<&str>, u32) = (PARSE_BOOL, 42); diff --git a/src/test/ui/consts/const-eval/transmute-const.stderr b/src/test/ui/consts/const-eval/transmute-const.stderr index 47f89fccf7a..e93a6887ba8 100644 --- a/src/test/ui/consts/const-eval/transmute-const.stderr +++ b/src/test/ui/consts/const-eval/transmute-const.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/transmute-const.rs:5:1 | LL | static FOO: bool = unsafe { mem::transmute(3u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3, but expected something less or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index 483285aa4e1..1922d59891f 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -1,34 +1,36 @@ +#![feature(const_transmute, never_type)] #![allow(const_err)] // make sure we cannot allow away the errors tested here +use std::mem; #[repr(transparent)] #[derive(Copy, Clone)] struct Wrap(T); +#[derive(Copy, Clone)] +enum Never {} + +// # simple enum with discriminant 0 + #[repr(usize)] #[derive(Copy, Clone)] enum Enum { A = 0, } -#[repr(C)] -union TransmuteEnum { - in1: &'static u8, - in2: usize, - out1: Enum, - out2: Wrap, -} -const GOOD_ENUM: Enum = unsafe { TransmuteEnum { in2: 0 }.out1 }; +const GOOD_ENUM: Enum = unsafe { mem::transmute(0usize) }; -const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 }; +const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; //~^ ERROR is undefined behavior -const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 }; +const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; //~^ ERROR is undefined behavior -const BAD_ENUM_WRAPPED: Wrap = unsafe { TransmuteEnum { in1: &1 }.out2 }; +const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; //~^ ERROR is undefined behavior +// # simple enum with discriminant 2 + // (Potentially) invalid enum discriminant #[repr(usize)] #[derive(Copy, Clone)] @@ -36,39 +38,58 @@ enum Enum2 { A = 2, } -#[repr(C)] -union TransmuteEnum2 { - in1: usize, - in2: &'static u8, - in3: (), - out1: Enum2, - out2: Wrap, // something wrapping the enum so that we test layout first, not enum - out3: Option, -} -const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; +const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; //~^ ERROR is undefined behavior -const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; +const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; //~^ ERROR is undefined behavior -const BAD_ENUM2_WRAPPED: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; +// something wrapping the enum so that we test layout first, not enum +const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; //~^ ERROR is undefined behavior // Undef enum discriminant. -const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 }; +#[repr(C)] +union MaybeUninit { + uninit: (), + init: T, +} +const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR is undefined behavior // Pointer value in an enum with a niche that is not just 0. -const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; +const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; //~^ ERROR is undefined behavior +// # valid discriminant for uninhabited variant + +// An enum with 3 variants of which some are uninhabited -- so the uninhabited variants *do* +// have a discriminant. +enum UninhDiscriminant { + A, + B(!), + C, + D(Never), +} + +const GOOD_INHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(0u8) }; // variant A +const GOOD_INHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(2u8) }; // variant C + +const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; +//~^ ERROR is undefined behavior +const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; +//~^ ERROR is undefined behavior + +// # other + // Invalid enum field content (mostly to test printing of paths for enum tuple // variants and tuples). -#[repr(C)] -union TransmuteChar { - a: u32, - b: char, -} // Need to create something which does not clash with enum layout optimizations. -const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); +const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); +//~^ ERROR is undefined behavior + +// All variants are uninhabited but also have data. +const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(1u64) }; +//~^ ERROR is undefined behavior +const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(1u64) }; //~^ ERROR is undefined behavior fn main() { diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index 8ebc9dbec8a..10a3d2fa1ab 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -1,75 +1,107 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:23:1 | -LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 1, but expected a valid enum discriminant +LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 1, but expected a valid enum discriminant | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:26:1 | -LL | const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant +LL | const BAD_ENUM_PTR: Enum = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:29:1 | -LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { TransmuteEnum { in1: &1 }.out2 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 0 +LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .0., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:48:1 + --> $DIR/ub-enum.rs:41:1 | -LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant +LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:50:1 + --> $DIR/ub-enum.rs:43:1 | -LL | const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant +LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:52:1 + --> $DIR/ub-enum.rs:46:1 | -LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 2 +LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at .0., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:56:1 + --> $DIR/ub-enum.rs:55:1 | -LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid enum discriminant +LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:60:1 + --> $DIR/ub-enum.rs:59:1 | -LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant +LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:71:1 + --> $DIR/ub-enum.rs:76:1 | -LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected something less or equal to 1114111 +LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at ..0 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. -error: aborting due to 9 previous errors +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:78:1 + | +LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at ..0 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:86:1 + | +LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected a valid unicode codepoint + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:90:1 + | +LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(1u64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at ..0.1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-enum.rs:92:1 + | +LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(1u64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Never at ..0.1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/ub-nonnull.rs b/src/test/ui/consts/const-eval/ub-nonnull.rs index 8ce64ced7df..1f46b6c98ad 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.rs +++ b/src/test/ui/consts/const-eval/ub-nonnull.rs @@ -25,11 +25,11 @@ const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value #[repr(C)] -union Transmute { +union MaybeUninit { uninit: (), - out: NonZeroU8, + init: T, } -const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out }; +const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR it is undefined behavior to use this value // Also test other uses of rustc_layout_scalar_valid_range_start diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr index 4d9d258f808..adad1b4f7fa 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr @@ -13,7 +13,7 @@ LL | / const OUT_OF_BOUNDS_PTR: NonNull = { unsafe { LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL! LL | | let out_of_bounds_ptr = &ptr[255]; - | | ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 8 which has size 1 + | | ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc8 which has size 1 LL | | mem::transmute(out_of_bounds_ptr) LL | | } }; | |____- @@ -43,8 +43,8 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:32:1 | -LL | const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected something greater or equal to 1 +LL | const UNINIT: NonZeroU8 = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes at .0, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-ref.rs b/src/test/ui/consts/const-eval/ub-ref.rs index 03ac12c8b1a..562ec99111b 100644 --- a/src/test/ui/consts/const-eval/ub-ref.rs +++ b/src/test/ui/consts/const-eval/ub-ref.rs @@ -6,11 +6,18 @@ use std::mem; const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; //~^ ERROR it is undefined behavior to use this value -//~^^ type validation failed: encountered unaligned reference (required 2 byte alignment but found 1) +//~^^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) + +const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; +//~^ ERROR it is undefined behavior to use this value +//~^^ type validation failed: encountered an unaligned box (required 2 byte alignment but found 1) const NULL: &u16 = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value +const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; +//~^ ERROR it is undefined behavior to use this value + // It is very important that we reject this: We do promote `&(4 * REF_AS_USIZE)`, // but that would fail to compile; so we ended up breaking user code that would // have worked fine had we not promoted. @@ -20,7 +27,13 @@ const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; //~^ ERROR it is undefined behavior to use this value +const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; +//~^ ERROR it is undefined behavior to use this value + const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; //~^ ERROR it is undefined behavior to use this value +const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; +//~^ ERROR it is undefined behavior to use this value + fn main() {} diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index 01bde413c0d..fb3df8ace4e 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -2,20 +2,36 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:7:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned reference (required 2 byte alignment but found 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered an unaligned reference (required 2 byte alignment but found 1) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:11:1 | +LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered an unaligned box (required 2 byte alignment but found 1) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref.rs:15:1 + | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL reference + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref.rs:18:1 + | +LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a NULL box | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:17:1 + --> $DIR/ub-ref.rs:24:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes @@ -23,7 +39,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:20:1 + --> $DIR/ub-ref.rs:27:1 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain (non-pointer) bytes @@ -31,13 +47,29 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:23:1 + --> $DIR/ub-ref.rs:30:1 + | +LL | const REF_AS_USIZE_BOX_SLICE: Box<[usize]> = unsafe { mem::transmute::<&[usize], _>(&[mem::transmute(&0)]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain (non-pointer) bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref.rs:33:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (created from integer) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (created from integer) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-ref.rs:36:1 + | +LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (created from integer) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. -error: aborting due to 5 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.rs b/src/test/ui/consts/const-eval/ub-uninhabit.rs index d2745d71bdb..e7350ae2716 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.rs +++ b/src/test/ui/consts/const-eval/ub-uninhabit.rs @@ -7,18 +7,18 @@ use std::mem; enum Bar {} #[repr(C)] -union TransmuteUnion { - a: A, - b: B, +union MaybeUninit { + uninit: (), + init: T, } -const BAD_BAD_BAD: Bar = unsafe { (TransmuteUnion::<(), Bar> { a: () }).b }; +const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR it is undefined behavior to use this value const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; //~^ ERROR it is undefined behavior to use this value -const BAD_BAD_ARRAY: [Bar; 1] = unsafe { (TransmuteUnion::<(), [Bar; 1]> { a: () }).b }; +const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; //~^ ERROR it is undefined behavior to use this value fn main() {} diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.stderr index 3877f3cab6d..8ce4279a8b7 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.stderr +++ b/src/test/ui/consts/const-eval/ub-uninhabit.stderr @@ -1,8 +1,8 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:15:1 | -LL | const BAD_BAD_BAD: Bar = unsafe { (TransmuteUnion::<(), Bar> { a: () }).b }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type +LL | const BAD_BAD_BAD: Bar = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -10,15 +10,15 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:18:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at . + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at . | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value --> $DIR/ub-uninhabit.rs:21:1 | -LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { (TransmuteUnion::<(), [Bar; 1]> { a: () }).b }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type +LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { MaybeUninit { uninit: () }.init }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Bar at [0] | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-upvars.stderr b/src/test/ui/consts/const-eval/ub-upvars.stderr index ea6ab3ae5b5..972c9eb38c8 100644 --- a/src/test/ui/consts/const-eval/ub-upvars.stderr +++ b/src/test/ui/consts/const-eval/ub-upvars.stderr @@ -6,7 +6,7 @@ LL | | let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) }; LL | | let another_var = 13; LL | | move || { let _ = bad_ref; let _ = another_var; } LL | | }; - | |__^ type validation failed: encountered 0 at ..., but expected something greater or equal to 1 + | |__^ type validation failed: encountered a NULL reference at ... | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs index a5c2a57c6c8..0200bfe9f08 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -1,72 +1,18 @@ // ignore-tidy-linelength +#![feature(const_transmute)] #![allow(unused)] #![allow(const_err)] // make sure we cannot allow away the errors tested here +use std::mem; + // normalize-stderr-test "offset \d+" -> "offset N" -// normalize-stderr-test "allocation \d+" -> "allocation N" +// normalize-stderr-test "alloc\d+" -> "allocN" // normalize-stderr-test "size \d+" -> "size N" #[repr(C)] -union BoolTransmute { - val: u8, - bl: bool, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct SliceRepr { - ptr: *const u8, - len: usize, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct BadSliceRepr { - ptr: *const u8, - len: &'static u8, -} - -#[repr(C)] -union SliceTransmute { - repr: SliceRepr, - bad: BadSliceRepr, - addr: usize, - slice: &'static [u8], - raw_slice: *const [u8], - str: &'static str, - my_str: &'static MyStr, - my_slice: &'static MySliceBool, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct DynRepr { - ptr: *const u8, - vtable: *const u8, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct DynRepr2 { - ptr: *const u8, - vtable: *const u64, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct BadDynRepr { - ptr: *const u8, - vtable: usize, -} - -#[repr(C)] -union DynTransmute { - repr: DynRepr, - repr2: DynRepr2, - bad: BadDynRepr, - addr: usize, - rust: &'static dyn Trait, - raw_rust: *const dyn Trait, +union MaybeUninit { + uninit: (), + init: T, } trait Trait {} @@ -81,90 +27,103 @@ type MySliceBool = MySlice<[bool]>; // # str // OK -const STR_VALID: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str}; +const STR_VALID: &str = unsafe { mem::transmute((&42u8, 1usize)) }; // bad str -const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; +const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; +//~^ ERROR it is undefined behavior to use this value +const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); //~^ ERROR it is undefined behavior to use this value // bad str -const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; +const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; //~^ ERROR it is undefined behavior to use this value // bad str in user-defined unsized type -const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; +const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; +//~^ ERROR it is undefined behavior to use this value +const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; //~^ ERROR it is undefined behavior to use this value // invalid UTF-8 -const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; +const STR_NO_UTF8: &str = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; //~^ ERROR it is undefined behavior to use this value // invalid UTF-8 in user-defined str-like -const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; +const MYSTR_NO_UTF8: &MyStr = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; //~^ ERROR it is undefined behavior to use this value // # slice // OK -const SLICE_VALID: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice}; +const SLICE_VALID: &[u8] = unsafe { mem::transmute((&42u8, 1usize)) }; // bad slice: length uninit -const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice}; +const SLICE_LENGTH_UNINIT: &[u8] = unsafe { //~^ ERROR it is undefined behavior to use this value + let uninit_len = MaybeUninit:: { uninit: () }; + mem::transmute((42, uninit_len)) +}; // bad slice: length too big -const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; +const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; //~^ ERROR it is undefined behavior to use this value // bad slice: length not an int -const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; +const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; +//~^ ERROR it is undefined behavior to use this value +// bad slice box: length too big +const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; +//~^ ERROR it is undefined behavior to use this value +// bad slice box: length not an int +const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; //~^ ERROR it is undefined behavior to use this value // bad data *inside* the slice -const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; +const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; //~^ ERROR it is undefined behavior to use this value // good MySliceBool const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]); // bad: sized field is not okay -const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); +const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); //~^ ERROR it is undefined behavior to use this value // bad: unsized part is not okay -const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); +const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); //~^ ERROR it is undefined behavior to use this value // # raw slice -const RAW_SLICE_VALID: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.raw_slice}; // ok -const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.raw_slice}; // ok because raw -const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: usize::max_value() } }.raw_slice}; // ok because raw -const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice}; +const RAW_SLICE_VALID: *const [u8] = unsafe { mem::transmute((&42u8, 1usize)) }; // ok +const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, 999usize)) }; // ok because raw +const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, usize::MAX)) }; // ok because raw +const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { //~^ ERROR it is undefined behavior to use this value + let uninit_len = MaybeUninit:: { uninit: () }; + mem::transmute((42, uninit_len)) +}; // # trait object // bad trait object -const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; +const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) }; //~^ ERROR it is undefined behavior to use this value // bad trait object -const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; +const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; //~^ ERROR it is undefined behavior to use this value // bad trait object -const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; +const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) }; //~^ ERROR it is undefined behavior to use this value // bad data *inside* the trait object -const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; +const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; //~^ ERROR it is undefined behavior to use this value // # raw trait object -const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.raw_rust}; +const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; //~^ ERROR it is undefined behavior to use this value -const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust}; +const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; //~^ ERROR it is undefined behavior to use this value -const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl } as *const _; // ok because raw +const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) } as *const dyn Trait; // ok because raw // Const eval fails for these, so they need to be statics to error. static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { - DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust + mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) //~^ ERROR could not evaluate static initializer }; static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { - DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust + mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) //~^ ERROR could not evaluate static initializer }; -fn main() { - let _ = RAW_TRAIT_OBJ_VTABLE_NULL; - let _ = RAW_TRAIT_OBJ_VTABLE_INVALID; -} +fn main() {} diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr index ce57d680dc9..80e60dbb58a 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr @@ -1,159 +1,199 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:86:1 + --> $DIR/ub-wide-ptr.rs:32:1 | -LL | const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds) +LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:89:1 + --> $DIR/ub-wide-ptr.rs:34:1 | -LL | const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer +LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object at .0 | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:92:1 + --> $DIR/ub-wide-ptr.rs:37:1 | -LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer +LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:96:1 + --> $DIR/ub-wide-ptr.rs:40:1 | -LL | const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at . +LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:99:1 + --> $DIR/ub-wide-ptr.rs:42:1 | -LL | const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at ..0 +LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:106:1 + --> $DIR/ub-wide-ptr.rs:46:1 | -LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined pointer +LL | const STR_NO_UTF8: &str = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at . | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:109:1 + --> $DIR/ub-wide-ptr.rs:49:1 + | +LL | const MYSTR_NO_UTF8: &MyStr = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at ..0 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:56:1 + | +LL | / const SLICE_LENGTH_UNINIT: &[u8] = unsafe { +LL | | +LL | | let uninit_len = MaybeUninit:: { uninit: () }; +LL | | mem::transmute((42, uninit_len)) +LL | | }; + | |__^ type validation failed: encountered undefined pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:62:1 | -LL | const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds) +LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:112:1 + --> $DIR/ub-wide-ptr.rs:65:1 | -LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer +LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:116:1 + --> $DIR/ub-wide-ptr.rs:68:1 | -LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .[0], but expected something less or equal to 1 +LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (going beyond the bounds of its allocation) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:122:1 + --> $DIR/ub-wide-ptr.rs:71:1 | -LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..0, but expected something less or equal to 1 +LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:125:1 + --> $DIR/ub-wide-ptr.rs:75:1 | -LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..1[0], but expected something less or equal to 1 +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .[0], but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:132:1 + --> $DIR/ub-wide-ptr.rs:81:1 | -LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined pointer +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..0, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:137:1 + --> $DIR/ub-wide-ptr.rs:84:1 | -LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..1[0], but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:140:1 + --> $DIR/ub-wide-ptr.rs:91:1 | -LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable +LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { +LL | | +LL | | let uninit_len = MaybeUninit:: { uninit: () }; +LL | | mem::transmute((42, uninit_len)) +LL | | }; + | |__^ type validation failed: encountered undefined pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:143:1 + --> $DIR/ub-wide-ptr.rs:99:1 + | +LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:102:1 | -LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable +LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:147:1 + --> $DIR/ub-wide-ptr.rs:105:1 + | +LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:109:1 | -LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected something less or equal to 1 +LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:151:1 + --> $DIR/ub-wide-ptr.rs:113:1 | -LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.raw_rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable +LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:153:1 + --> $DIR/ub-wide-ptr.rs:115:1 | -LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable +LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:159:5 + --> $DIR/ub-wide-ptr.rs:121:5 | -LL | DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid use of NULL pointer +LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid use of NULL pointer error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:163:5 + --> $DIR/ub-wide-ptr.rs:125:5 | -LL | DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocation N which has size N +LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocN which has size N -error: aborting due to 20 previous errors +error: aborting due to 24 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/union-ub.stderr b/src/test/ui/consts/const-eval/union-ub.stderr index fa67bc0d8e7..9d90d6e8548 100644 --- a/src/test/ui/consts/const-eval/union-ub.stderr +++ b/src/test/ui/consts/const-eval/union-ub.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/union-ub.rs:31:1 | LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something less or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr index c98e206e88c..cede356a6b8 100644 --- a/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr +++ b/src/test/ui/consts/const-eval/validate_uninhabited_zsts.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | unsafe { std::mem::transmute(()) } | ^^^^^^^^^^^^^^^^^^^^^^^ | | - | entering unreachable code + | transmuting to uninhabited type | inside call to `foo` at $DIR/validate_uninhabited_zsts.rs:14:26 ... LL | const FOO: [Empty; 3] = [foo(); 3]; @@ -20,7 +20,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_uninhabited_zsts.rs:17:1 | LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Empty at [0] | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/zst_operand_eval.rs b/src/test/ui/consts/const-eval/zst_operand_eval.rs index 7edb6bd03da..5f7ddf7f758 100644 --- a/src/test/ui/consts/const-eval/zst_operand_eval.rs +++ b/src/test/ui/consts/const-eval/zst_operand_eval.rs @@ -1,4 +1,4 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass static ASSERT: () = [()][!(std::mem::size_of::() == 4) as usize]; diff --git a/src/test/ui/consts/const-int-arithmetic-overflow.rs b/src/test/ui/consts/const-int-arithmetic-overflow.rs index 75dac812f1e..99bbeaafda5 100644 --- a/src/test/ui/consts/const-int-arithmetic-overflow.rs +++ b/src/test/ui/consts/const-int-arithmetic-overflow.rs @@ -8,7 +8,7 @@ const fn add(x: i8, y: i8) -> i8 { x+y } const fn sub(x: i8, y: i8) -> i8 { x-y } const fn mul(x: i8, y: i8) -> i8 { x*y } -// div and rem are always checked, so we cannot test their result in case of oveflow. +// div and rem are always checked, so we cannot test their result in case of overflow. const fn neg(x: i8) -> i8 { -x } fn main() { diff --git a/src/test/ui/consts/const-int-conversion-rpass.rs b/src/test/ui/consts/const-int-conversion-rpass.rs index d52dbbae1e7..6484169dd9a 100644 --- a/src/test/ui/consts/const-int-conversion-rpass.rs +++ b/src/test/ui/consts/const-int-conversion-rpass.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(const_int_conversion)] - const REVERSE: u32 = 0x12345678_u32.reverse_bits(); const FROM_BE_BYTES: i32 = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]); const FROM_LE_BYTES: i32 = i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]); diff --git a/src/test/ui/consts/const-int-pow-rpass.rs b/src/test/ui/consts/const-int-pow-rpass.rs index 8e84a900605..b0fba19455b 100644 --- a/src/test/ui/consts/const-int-pow-rpass.rs +++ b/src/test/ui/consts/const-int-pow-rpass.rs @@ -1,11 +1,48 @@ // run-pass +#![feature(const_int_pow)] +#![feature(wrapping_next_power_of_two)] + const IS_POWER_OF_TWO_A: bool = 0u32.is_power_of_two(); const IS_POWER_OF_TWO_B: bool = 32u32.is_power_of_two(); const IS_POWER_OF_TWO_C: bool = 33u32.is_power_of_two(); +const POW: u8 = 3u8.pow(5); + +const CHECKED_POW_OK: Option = 3u8.checked_pow(5); +const CHECKED_POW_OVERFLOW: Option = 3u8.checked_pow(6); + +const WRAPPING_POW: u8 = 3u8.wrapping_pow(6); +const OVERFLOWING_POW: (u8, bool) = 3u8.overflowing_pow(6); +const SATURATING_POW: u8 = 3u8.saturating_pow(6); + +const NEXT_POWER_OF_TWO: u32 = 3u32.next_power_of_two(); + +const CHECKED_NEXT_POWER_OF_TWO_OK: Option = 3u32.checked_next_power_of_two(); +const CHECKED_NEXT_POWER_OF_TWO_OVERFLOW: Option = + u32::max_value().checked_next_power_of_two(); + +const WRAPPING_NEXT_POWER_OF_TWO: u32 = + u32::max_value().wrapping_next_power_of_two(); + fn main() { assert!(!IS_POWER_OF_TWO_A); assert!(IS_POWER_OF_TWO_B); assert!(!IS_POWER_OF_TWO_C); + + assert_eq!(POW, 243); + + assert_eq!(CHECKED_POW_OK, Some(243)); + assert_eq!(CHECKED_POW_OVERFLOW, None); + + assert_eq!(WRAPPING_POW, 217); + assert_eq!(OVERFLOWING_POW, (217, true)); + assert_eq!(SATURATING_POW, u8::max_value()); + + assert_eq!(NEXT_POWER_OF_TWO, 4); + + assert_eq!(CHECKED_NEXT_POWER_OF_TWO_OK, Some(4)); + assert_eq!(CHECKED_NEXT_POWER_OF_TWO_OVERFLOW, None); + + assert_eq!(WRAPPING_NEXT_POWER_OF_TWO, 0); } diff --git a/src/test/ui/consts/const-int-unchecked.stderr b/src/test/ui/consts/const-int-unchecked.stderr index bf31e0b0732..cf70454b6bf 100644 --- a/src/test/ui/consts/const-int-unchecked.stderr +++ b/src/test/ui/consts/const-int-unchecked.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const SHL_U8: u8 = unsafe { intrinsics::unchecked_shl(5_u8, 8) }; | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 8 in `unchecked_shl` + | overflowing shift by 8 in `unchecked_shl` | = note: `#[deny(const_err)]` on by default @@ -14,7 +14,7 @@ error: any use of this value will cause an error LL | const SHL_U16: u16 = unsafe { intrinsics::unchecked_shl(5_u16, 16) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 16 in `unchecked_shl` + | overflowing shift by 16 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:19:31 @@ -22,7 +22,7 @@ error: any use of this value will cause an error LL | const SHL_U32: u32 = unsafe { intrinsics::unchecked_shl(5_u32, 32) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 32 in `unchecked_shl` + | overflowing shift by 32 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:21:31 @@ -30,7 +30,7 @@ error: any use of this value will cause an error LL | const SHL_U64: u64 = unsafe { intrinsics::unchecked_shl(5_u64, 64) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 64 in `unchecked_shl` + | overflowing shift by 64 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:23:33 @@ -38,7 +38,7 @@ error: any use of this value will cause an error LL | const SHL_U128: u128 = unsafe { intrinsics::unchecked_shl(5_u128, 128) }; | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 128 in `unchecked_shl` + | overflowing shift by 128 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:28:29 @@ -46,7 +46,7 @@ error: any use of this value will cause an error LL | const SHL_I8: i8 = unsafe { intrinsics::unchecked_shl(5_i8, 8) }; | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 8 in `unchecked_shl` + | overflowing shift by 8 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:30:31 @@ -54,7 +54,7 @@ error: any use of this value will cause an error LL | const SHL_I16: i16 = unsafe { intrinsics::unchecked_shl(5_16, 16) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 16 in `unchecked_shl` + | overflowing shift by 16 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:32:31 @@ -62,7 +62,7 @@ error: any use of this value will cause an error LL | const SHL_I32: i32 = unsafe { intrinsics::unchecked_shl(5_i32, 32) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 32 in `unchecked_shl` + | overflowing shift by 32 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:34:31 @@ -70,7 +70,7 @@ error: any use of this value will cause an error LL | const SHL_I64: i64 = unsafe { intrinsics::unchecked_shl(5_i64, 64) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 64 in `unchecked_shl` + | overflowing shift by 64 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:36:33 @@ -78,7 +78,7 @@ error: any use of this value will cause an error LL | const SHL_I128: i128 = unsafe { intrinsics::unchecked_shl(5_i128, 128) }; | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 128 in `unchecked_shl` + | overflowing shift by 128 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:41:33 @@ -86,7 +86,7 @@ error: any use of this value will cause an error LL | const SHL_I8_NEG: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -1) }; | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 255 in `unchecked_shl` + | overflowing shift by 255 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:43:35 @@ -94,7 +94,7 @@ error: any use of this value will cause an error LL | const SHL_I16_NEG: i16 = unsafe { intrinsics::unchecked_shl(5_16, -1) }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 65535 in `unchecked_shl` + | overflowing shift by 65535 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:45:35 @@ -102,7 +102,7 @@ error: any use of this value will cause an error LL | const SHL_I32_NEG: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -1) }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 4294967295 in `unchecked_shl` + | overflowing shift by 4294967295 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:47:35 @@ -110,7 +110,7 @@ error: any use of this value will cause an error LL | const SHL_I64_NEG: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -1) }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 18446744073709551615 in `unchecked_shl` + | overflowing shift by 18446744073709551615 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:49:37 @@ -118,7 +118,7 @@ error: any use of this value will cause an error LL | const SHL_I128_NEG: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -1) }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 340282366920938463463374607431768211455 in `unchecked_shl` + | overflowing shift by 340282366920938463463374607431768211455 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:55:40 @@ -126,7 +126,7 @@ error: any use of this value will cause an error LL | const SHL_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shl(5_i8, -6) }; | ---------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 250 in `unchecked_shl` + | overflowing shift by 250 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:57:42 @@ -134,7 +134,7 @@ error: any use of this value will cause an error LL | const SHL_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shl(5_16, -13) }; | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 65523 in `unchecked_shl` + | overflowing shift by 65523 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:59:42 @@ -142,7 +142,7 @@ error: any use of this value will cause an error LL | const SHL_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shl(5_i32, -25) }; | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 4294967271 in `unchecked_shl` + | overflowing shift by 4294967271 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:61:42 @@ -150,7 +150,7 @@ error: any use of this value will cause an error LL | const SHL_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shl(5_i64, -30) }; | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 18446744073709551586 in `unchecked_shl` + | overflowing shift by 18446744073709551586 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:63:44 @@ -158,7 +158,7 @@ error: any use of this value will cause an error LL | const SHL_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shl(5_i128, -93) }; | -------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 340282366920938463463374607431768211363 in `unchecked_shl` + | overflowing shift by 340282366920938463463374607431768211363 in `unchecked_shl` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:70:29 @@ -166,7 +166,7 @@ error: any use of this value will cause an error LL | const SHR_U8: u8 = unsafe { intrinsics::unchecked_shr(5_u8, 8) }; | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 8 in `unchecked_shr` + | overflowing shift by 8 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:72:31 @@ -174,7 +174,7 @@ error: any use of this value will cause an error LL | const SHR_U16: u16 = unsafe { intrinsics::unchecked_shr(5_u16, 16) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 16 in `unchecked_shr` + | overflowing shift by 16 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:74:31 @@ -182,7 +182,7 @@ error: any use of this value will cause an error LL | const SHR_U32: u32 = unsafe { intrinsics::unchecked_shr(5_u32, 32) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 32 in `unchecked_shr` + | overflowing shift by 32 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:76:31 @@ -190,7 +190,7 @@ error: any use of this value will cause an error LL | const SHR_U64: u64 = unsafe { intrinsics::unchecked_shr(5_u64, 64) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 64 in `unchecked_shr` + | overflowing shift by 64 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:78:33 @@ -198,7 +198,7 @@ error: any use of this value will cause an error LL | const SHR_U128: u128 = unsafe { intrinsics::unchecked_shr(5_u128, 128) }; | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 128 in `unchecked_shr` + | overflowing shift by 128 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:83:29 @@ -206,7 +206,7 @@ error: any use of this value will cause an error LL | const SHR_I8: i8 = unsafe { intrinsics::unchecked_shr(5_i8, 8) }; | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 8 in `unchecked_shr` + | overflowing shift by 8 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:85:31 @@ -214,7 +214,7 @@ error: any use of this value will cause an error LL | const SHR_I16: i16 = unsafe { intrinsics::unchecked_shr(5_16, 16) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 16 in `unchecked_shr` + | overflowing shift by 16 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:87:31 @@ -222,7 +222,7 @@ error: any use of this value will cause an error LL | const SHR_I32: i32 = unsafe { intrinsics::unchecked_shr(5_i32, 32) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 32 in `unchecked_shr` + | overflowing shift by 32 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:89:31 @@ -230,7 +230,7 @@ error: any use of this value will cause an error LL | const SHR_I64: i64 = unsafe { intrinsics::unchecked_shr(5_i64, 64) }; | ------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 64 in `unchecked_shr` + | overflowing shift by 64 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:91:33 @@ -238,7 +238,7 @@ error: any use of this value will cause an error LL | const SHR_I128: i128 = unsafe { intrinsics::unchecked_shr(5_i128, 128) }; | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 128 in `unchecked_shr` + | overflowing shift by 128 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:96:33 @@ -246,7 +246,7 @@ error: any use of this value will cause an error LL | const SHR_I8_NEG: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -1) }; | --------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 255 in `unchecked_shr` + | overflowing shift by 255 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:98:35 @@ -254,7 +254,7 @@ error: any use of this value will cause an error LL | const SHR_I16_NEG: i16 = unsafe { intrinsics::unchecked_shr(5_16, -1) }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 65535 in `unchecked_shr` + | overflowing shift by 65535 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:100:35 @@ -262,7 +262,7 @@ error: any use of this value will cause an error LL | const SHR_I32_NEG: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -1) }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 4294967295 in `unchecked_shr` + | overflowing shift by 4294967295 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:102:35 @@ -270,7 +270,7 @@ error: any use of this value will cause an error LL | const SHR_I64_NEG: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -1) }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 18446744073709551615 in `unchecked_shr` + | overflowing shift by 18446744073709551615 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:104:37 @@ -278,7 +278,7 @@ error: any use of this value will cause an error LL | const SHR_I128_NEG: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -1) }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 340282366920938463463374607431768211455 in `unchecked_shr` + | overflowing shift by 340282366920938463463374607431768211455 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:110:40 @@ -286,7 +286,7 @@ error: any use of this value will cause an error LL | const SHR_I8_NEG_RANDOM: i8 = unsafe { intrinsics::unchecked_shr(5_i8, -6) }; | ---------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 250 in `unchecked_shr` + | overflowing shift by 250 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:112:42 @@ -294,7 +294,7 @@ error: any use of this value will cause an error LL | const SHR_I16_NEG_RANDOM: i16 = unsafe { intrinsics::unchecked_shr(5_16, -13) }; | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 65523 in `unchecked_shr` + | overflowing shift by 65523 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:114:42 @@ -302,7 +302,7 @@ error: any use of this value will cause an error LL | const SHR_I32_NEG_RANDOM: i32 = unsafe { intrinsics::unchecked_shr(5_i32, -25) }; | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 4294967271 in `unchecked_shr` + | overflowing shift by 4294967271 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:116:42 @@ -310,7 +310,7 @@ error: any use of this value will cause an error LL | const SHR_I64_NEG_RANDOM: i64 = unsafe { intrinsics::unchecked_shr(5_i64, -30) }; | -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 18446744073709551586 in `unchecked_shr` + | overflowing shift by 18446744073709551586 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:118:44 @@ -318,7 +318,7 @@ error: any use of this value will cause an error LL | const SHR_I128_NEG_RANDOM: i128 = unsafe { intrinsics::unchecked_shr(5_i128, -93) }; | -------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflowing shift by 340282366920938463463374607431768211363 in `unchecked_shr` + | overflowing shift by 340282366920938463463374607431768211363 in `unchecked_shr` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:123:25 @@ -326,7 +326,7 @@ error: any use of this value will cause an error LL | const _: u16 = unsafe { std::intrinsics::unchecked_add(40000u16, 30000) }; | ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflow executing `unchecked_add` + | overflow executing `unchecked_add` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:126:25 @@ -334,7 +334,7 @@ error: any use of this value will cause an error LL | const _: u32 = unsafe { std::intrinsics::unchecked_sub(14u32, 22) }; | ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflow executing `unchecked_sub` + | overflow executing `unchecked_sub` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:129:25 @@ -342,7 +342,7 @@ error: any use of this value will cause an error LL | const _: u16 = unsafe { std::intrinsics::unchecked_mul(300u16, 250u16) }; | ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflow executing `unchecked_mul` + | overflow executing `unchecked_mul` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:132:25 @@ -358,7 +358,7 @@ error: any use of this value will cause an error LL | const _: i32 = unsafe { std::intrinsics::unchecked_div(i32::min_value(), -1) }; | ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflow executing `unchecked_div` + | overflow executing `unchecked_div` error: any use of this value will cause an error --> $DIR/const-int-unchecked.rs:137:25 @@ -374,7 +374,7 @@ error: any use of this value will cause an error LL | const _: i32 = unsafe { std::intrinsics::unchecked_rem(i32::min_value(), -1) }; | ------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- | | - | Overflow executing `unchecked_rem` + | overflow executing `unchecked_rem` error: aborting due to 47 previous errors diff --git a/src/test/ui/consts/const-points-to-static.stderr b/src/test/ui/consts/const-points-to-static.stderr index 8949358e293..f2ca7ff7825 100644 --- a/src/test/ui/consts/const-points-to-static.stderr +++ b/src/test/ui/consts/const-points-to-static.stderr @@ -8,7 +8,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-points-to-static.rs:5:1 | LL | const TEST: &u8 = &MY_STATIC; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to a static variable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-prop-ice.rs b/src/test/ui/consts/const-prop-ice.rs index 8682d2ee901..5bffe020629 100644 --- a/src/test/ui/consts/const-prop-ice.rs +++ b/src/test/ui/consts/const-prop-ice.rs @@ -1,5 +1,5 @@ // build-fail fn main() { - [0; 3][3u64 as usize]; //~ ERROR the len is 3 but the index is 3 + [0; 3][3u64 as usize]; //~ ERROR this operation will panic at runtime } diff --git a/src/test/ui/consts/const-prop-ice.stderr b/src/test/ui/consts/const-prop-ice.stderr index 65502a4ff71..7bb4acb235a 100644 --- a/src/test/ui/consts/const-prop-ice.stderr +++ b/src/test/ui/consts/const-prop-ice.stderr @@ -1,10 +1,10 @@ -error: index out of bounds: the len is 3 but the index is 3 +error: this operation will panic at runtime --> $DIR/const-prop-ice.rs:4:5 | LL | [0; 3][3u64 as usize]; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 3 | - = note: `#[deny(const_err)]` on by default + = note: `#[deny(unconditional_panic)]` on by default error: aborting due to previous error diff --git a/src/test/ui/consts/const-prop-ice2.rs b/src/test/ui/consts/const-prop-ice2.rs index 6a73483026f..d533e394c06 100644 --- a/src/test/ui/consts/const-prop-ice2.rs +++ b/src/test/ui/consts/const-prop-ice2.rs @@ -3,5 +3,5 @@ fn main() { enum Enum { One=1 } let xs=[0;1 as usize]; - println!("{}", xs[Enum::One as usize]); //~ ERROR the len is 1 but the index is 1 + println!("{}", xs[Enum::One as usize]); //~ ERROR this operation will panic at runtime } diff --git a/src/test/ui/consts/const-prop-ice2.stderr b/src/test/ui/consts/const-prop-ice2.stderr index cbb8fde80f9..73405eca340 100644 --- a/src/test/ui/consts/const-prop-ice2.stderr +++ b/src/test/ui/consts/const-prop-ice2.stderr @@ -1,10 +1,10 @@ -error: index out of bounds: the len is 1 but the index is 1 +error: this operation will panic at runtime --> $DIR/const-prop-ice2.rs:6:20 | LL | println!("{}", xs[Enum::One as usize]); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 | - = note: `#[deny(const_err)]` on by default + = note: `#[deny(unconditional_panic)]` on by default error: aborting due to previous error diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs new file mode 100644 index 00000000000..1ad5134e71c --- /dev/null +++ b/src/test/ui/consts/const_discriminant.rs @@ -0,0 +1,40 @@ +// run-pass +#![feature(const_discriminant)] +#![allow(dead_code)] + +use std::mem::{discriminant, Discriminant}; + +// `discriminant(const_expr)` may get const-propagated. +// As we want to check that const-eval is equal to ordinary exection, +// we wrap `const_expr` with a function which is not const to prevent this. +#[inline(never)] +fn identity(x: T) -> T { x } + +enum Test { + A(u8), + B, + C { a: u8, b: u8 }, +} + +const TEST_A: Discriminant = discriminant(&Test::A(5)); +const TEST_A_OTHER: Discriminant = discriminant(&Test::A(17)); +const TEST_B: Discriminant = discriminant(&Test::B); + +enum Void {} + +enum SingleVariant { + V, + Never(Void), +} + +const TEST_V: Discriminant = discriminant(&SingleVariant::V); + +fn main() { + assert_eq!(TEST_A, TEST_A_OTHER); + assert_eq!(TEST_A, discriminant(identity(&Test::A(17)))); + assert_eq!(TEST_B, discriminant(identity(&Test::B))); + assert_ne!(TEST_A, TEST_B); + assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 }))); + + assert_eq!(TEST_V, discriminant(identity(&SingleVariant::V))); +} diff --git a/src/test/ui/consts/const_let_eq.rs b/src/test/ui/consts/const_let_eq.rs index a2364c392f2..818819f9ff6 100644 --- a/src/test/ui/consts/const_let_eq.rs +++ b/src/test/ui/consts/const_let_eq.rs @@ -5,6 +5,7 @@ struct Bar { x: T } struct W(u32); struct A { a: u32 } +#[allow(redundant_semicolons)] const fn basics((a,): (u32,)) -> u32 { // Deferred assignment: let b: u32; diff --git a/src/test/ui/consts/const_let_eq_float.rs b/src/test/ui/consts/const_let_eq_float.rs index 0c927a0484d..bc0ef26eb2f 100644 --- a/src/test/ui/consts/const_let_eq_float.rs +++ b/src/test/ui/consts/const_let_eq_float.rs @@ -7,6 +7,7 @@ struct Bar { x: T } struct W(f32); struct A { a: f32 } +#[allow(redundant_semicolons)] const fn basics((a,): (f32,)) -> f32 { // Deferred assignment: let b: f32; diff --git a/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs b/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs new file mode 100644 index 00000000000..4ed908312fb --- /dev/null +++ b/src/test/ui/consts/const_limit/const_eval_limit_not_reached.rs @@ -0,0 +1,15 @@ +// check-pass +#![feature(const_eval_limit)] +#![const_eval_limit="1000"] + +const CONSTANT: usize = limit(); + +fn main() { + assert_eq!(CONSTANT, 1764); +} + +const fn limit() -> usize { + let x = 42; + + x * 42 +} diff --git a/src/test/ui/consts/const_limit/const_eval_limit_overflow.rs b/src/test/ui/consts/const_limit/const_eval_limit_overflow.rs new file mode 100644 index 00000000000..1c49593cd53 --- /dev/null +++ b/src/test/ui/consts/const_limit/const_eval_limit_overflow.rs @@ -0,0 +1,15 @@ +#![feature(const_eval_limit)] +#![const_eval_limit="18_446_744_073_709_551_615"] +//~^ ERROR `limit` must be a non-negative integer + +const CONSTANT: usize = limit(); + +fn main() { + assert_eq!(CONSTANT, 1764); +} + +const fn limit() -> usize { + let x = 42; + + x * 42 +} diff --git a/src/test/ui/consts/const_limit/const_eval_limit_overflow.stderr b/src/test/ui/consts/const_limit/const_eval_limit_overflow.stderr new file mode 100644 index 00000000000..7f5d5e6cd4c --- /dev/null +++ b/src/test/ui/consts/const_limit/const_eval_limit_overflow.stderr @@ -0,0 +1,10 @@ +error: `limit` must be a non-negative integer + --> $DIR/const_eval_limit_overflow.rs:2:1 + | +LL | #![const_eval_limit="18_446_744_073_709_551_615"] + | ^^^^^^^^^^^^^^^^^^^^----------------------------^ + | | + | not a valid integer + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.rs b/src/test/ui/consts/const_limit/const_eval_limit_reached.rs new file mode 100644 index 00000000000..d962398d413 --- /dev/null +++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength +// only-x86_64 +// check-pass +// NOTE: We always compile this test with -Copt-level=0 because higher opt-levels +// optimize away the const function +// compile-flags:-Copt-level=0 +#![feature(const_eval_limit)] +#![const_eval_limit="2"] + +const CONSTANT: usize = limit(); +//~^ WARNING Constant evaluating a complex constant, this might take some time + +fn main() { + assert_eq!(CONSTANT, 1764); +} + +const fn limit() -> usize { //~ WARNING Constant evaluating a complex constant, this might take some time + let x = 42; + + x * 42 +} diff --git a/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr new file mode 100644 index 00000000000..e0871ff7185 --- /dev/null +++ b/src/test/ui/consts/const_limit/const_eval_limit_reached.stderr @@ -0,0 +1,16 @@ +warning: Constant evaluating a complex constant, this might take some time + --> $DIR/const_eval_limit_reached.rs:17:1 + | +LL | / const fn limit() -> usize { +LL | | let x = 42; +LL | | +LL | | x * 42 +LL | | } + | |_^ + +warning: Constant evaluating a complex constant, this might take some time + --> $DIR/const_eval_limit_reached.rs:10:1 + | +LL | const CONSTANT: usize = limit(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.rs b/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.rs new file mode 100644 index 00000000000..61119d7511d --- /dev/null +++ b/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.rs @@ -0,0 +1,14 @@ +#![const_eval_limit="42"] +//~^ ERROR the `#[const_eval_limit]` attribute is an experimental feature [E0658] + +const CONSTANT: usize = limit(); + +fn main() { + assert_eq!(CONSTANT, 1764); +} + +const fn limit() -> usize { + let x = 42; + + x * 42 +} diff --git a/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.stderr b/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.stderr new file mode 100644 index 00000000000..5bd29c7dfd2 --- /dev/null +++ b/src/test/ui/consts/const_limit/feature-gate-const_eval_limit.stderr @@ -0,0 +1,12 @@ +error[E0658]: the `#[const_eval_limit]` attribute is an experimental feature + --> $DIR/feature-gate-const_eval_limit.rs:1:1 + | +LL | #![const_eval_limit="42"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #67217 for more information + = help: add `#![feature(const_eval_limit)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/dangling-alloc-id-ice.stderr b/src/test/ui/consts/dangling-alloc-id-ice.stderr index bac9f555d27..0e213555052 100644 --- a/src/test/ui/consts/dangling-alloc-id-ice.stderr +++ b/src/test/ui/consts/dangling-alloc-id-ice.stderr @@ -5,7 +5,7 @@ LL | / const FOO: &() = { LL | | let y = (); LL | | unsafe { Foo { y: &y }.long_live_the_unit } LL | | }; - | |__^ type validation failed: encountered dangling pointer in final constant + | |__^ encountered dangling pointer in final constant | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/dangling_raw_ptr.stderr b/src/test/ui/consts/dangling_raw_ptr.stderr index 4748be37dff..4d4c2876c45 100644 --- a/src/test/ui/consts/dangling_raw_ptr.stderr +++ b/src/test/ui/consts/dangling_raw_ptr.stderr @@ -5,7 +5,7 @@ LL | / const FOO: *const u32 = { LL | | let x = 42; LL | | &x LL | | }; - | |__^ type validation failed: encountered dangling pointer in final constant + | |__^ encountered dangling pointer in final constant | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/std/char.rs b/src/test/ui/consts/is_ascii.rs similarity index 54% rename from src/test/ui/consts/std/char.rs rename to src/test/ui/consts/is_ascii.rs index fe79059a2e4..d8424549f93 100644 --- a/src/test/ui/consts/std/char.rs +++ b/src/test/ui/consts/is_ascii.rs @@ -3,7 +3,13 @@ static X: bool = 'a'.is_ascii(); static Y: bool = 'ä'.is_ascii(); +static BX: bool = b'a'.is_ascii(); +static BY: bool = 192u8.is_ascii(); + fn main() { assert!(X); assert!(!Y); + + assert!(BX); + assert!(!BY); } diff --git a/src/test/ui/consts/issue-63952.rs b/src/test/ui/consts/issue-63952.rs new file mode 100644 index 00000000000..35cbc7003f0 --- /dev/null +++ b/src/test/ui/consts/issue-63952.rs @@ -0,0 +1,28 @@ +// Regression test for #63952, shouldn't hang. + +use std::usize; + +#[repr(C)] +#[derive(Copy, Clone)] +struct SliceRepr { + ptr: *const u8, + len: usize, +} + +union SliceTransmute { + repr: SliceRepr, + slice: &'static [u8], +} + +// bad slice: length too big to even exist anywhere +const SLICE_WAY_TOO_LONG: &[u8] = unsafe { //~ ERROR: it is undefined behavior to use this value + SliceTransmute { + repr: SliceRepr { + ptr: &42, + len: usize::MAX, + }, + } + .slice +}; + +fn main() {} diff --git a/src/test/ui/consts/issue-63952.stderr b/src/test/ui/consts/issue-63952.stderr new file mode 100644 index 00000000000..5e85be45b16 --- /dev/null +++ b/src/test/ui/consts/issue-63952.stderr @@ -0,0 +1,17 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/issue-63952.rs:18:1 + | +LL | / const SLICE_WAY_TOO_LONG: &[u8] = unsafe { +LL | | SliceTransmute { +LL | | repr: SliceRepr { +LL | | ptr: &42, +... | +LL | | .slice +LL | | }; + | |__^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/issue-64059-2.rs b/src/test/ui/consts/issue-64059-2.rs deleted file mode 100644 index 38911c3dcf6..00000000000 --- a/src/test/ui/consts/issue-64059-2.rs +++ /dev/null @@ -1,6 +0,0 @@ -// compile-flags: -C overflow-checks=on -O -// run-pass - -fn main() { - let _ = -(-0.0); -} diff --git a/src/test/ui/consts/issue-64059.rs b/src/test/ui/consts/issue-64059.rs index c4c895fef66..02c8b725032 100644 --- a/src/test/ui/consts/issue-64059.rs +++ b/src/test/ui/consts/issue-64059.rs @@ -1,3 +1,8 @@ +// revisions: noopt opt opt_with_overflow_checks +//[noopt]compile-flags: -C opt-level=0 +//[opt]compile-flags: -O +//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O + // run-pass fn main() { diff --git a/src/test/ui/consts/issue-68684.rs b/src/test/ui/consts/issue-68684.rs new file mode 100644 index 00000000000..c98f199b60e --- /dev/null +++ b/src/test/ui/consts/issue-68684.rs @@ -0,0 +1,15 @@ +// check-pass + +enum _Enum { + A(), +} + +type _E = _Enum; + +const fn _a() -> _Enum { + _E::A() +} + +const _A: _Enum = _a(); + +fn main() {} diff --git a/src/test/ui/consts/issue-69020.noopt.stderr b/src/test/ui/consts/issue-69020.noopt.stderr new file mode 100644 index 00000000000..c48a106ef46 --- /dev/null +++ b/src/test/ui/consts/issue-69020.noopt.stderr @@ -0,0 +1,30 @@ +error: this arithmetic operation will overflow + --> $DIR/issue-69020.rs:21:22 + | +LL | const NEG: i32 = -i32::MIN + T::NEG; + | ^^^^^^^^^ attempt to negate with overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/issue-69020.rs:23:22 + | +LL | const ADD: i32 = (i32::MAX+1) + T::ADD; + | ^^^^^^^^^^^^ attempt to add with overflow + +error: this operation will panic at runtime + --> $DIR/issue-69020.rs:25:22 + | +LL | const DIV: i32 = (1/0) + T::DIV; + | ^^^^^ attempt to divide by zero + | + = note: `#[deny(unconditional_panic)]` on by default + +error: this operation will panic at runtime + --> $DIR/issue-69020.rs:27:22 + | +LL | const OOB: i32 = [1][1] + T::OOB; + | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/consts/issue-69020.opt.stderr b/src/test/ui/consts/issue-69020.opt.stderr new file mode 100644 index 00000000000..c48a106ef46 --- /dev/null +++ b/src/test/ui/consts/issue-69020.opt.stderr @@ -0,0 +1,30 @@ +error: this arithmetic operation will overflow + --> $DIR/issue-69020.rs:21:22 + | +LL | const NEG: i32 = -i32::MIN + T::NEG; + | ^^^^^^^^^ attempt to negate with overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/issue-69020.rs:23:22 + | +LL | const ADD: i32 = (i32::MAX+1) + T::ADD; + | ^^^^^^^^^^^^ attempt to add with overflow + +error: this operation will panic at runtime + --> $DIR/issue-69020.rs:25:22 + | +LL | const DIV: i32 = (1/0) + T::DIV; + | ^^^^^ attempt to divide by zero + | + = note: `#[deny(unconditional_panic)]` on by default + +error: this operation will panic at runtime + --> $DIR/issue-69020.rs:27:22 + | +LL | const OOB: i32 = [1][1] + T::OOB; + | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/consts/issue-69020.opt_with_overflow_checks.stderr b/src/test/ui/consts/issue-69020.opt_with_overflow_checks.stderr new file mode 100644 index 00000000000..c48a106ef46 --- /dev/null +++ b/src/test/ui/consts/issue-69020.opt_with_overflow_checks.stderr @@ -0,0 +1,30 @@ +error: this arithmetic operation will overflow + --> $DIR/issue-69020.rs:21:22 + | +LL | const NEG: i32 = -i32::MIN + T::NEG; + | ^^^^^^^^^ attempt to negate with overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/issue-69020.rs:23:22 + | +LL | const ADD: i32 = (i32::MAX+1) + T::ADD; + | ^^^^^^^^^^^^ attempt to add with overflow + +error: this operation will panic at runtime + --> $DIR/issue-69020.rs:25:22 + | +LL | const DIV: i32 = (1/0) + T::DIV; + | ^^^^^ attempt to divide by zero + | + = note: `#[deny(unconditional_panic)]` on by default + +error: this operation will panic at runtime + --> $DIR/issue-69020.rs:27:22 + | +LL | const OOB: i32 = [1][1] + T::OOB; + | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/consts/issue-69020.rs b/src/test/ui/consts/issue-69020.rs new file mode 100644 index 00000000000..e079feb04d4 --- /dev/null +++ b/src/test/ui/consts/issue-69020.rs @@ -0,0 +1,29 @@ +// revisions: noopt opt opt_with_overflow_checks +//[noopt]compile-flags: -C opt-level=0 +//[opt]compile-flags: -O +//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O + +#![crate_type="lib"] + +use std::i32; + +pub trait Foo { + const NEG: i32; + const ADD: i32; + const DIV: i32; + const OOB: i32; +} + +// These constants cannot be evaluated already (they depend on `T::N`), so +// they can just be linted like normal run-time code. But codegen works +// a bit different in const context, so this test makes sure that we still catch overflow. +impl Foo for Vec { + const NEG: i32 = -i32::MIN + T::NEG; + //~^ ERROR arithmetic operation will overflow + const ADD: i32 = (i32::MAX+1) + T::ADD; + //~^ ERROR arithmetic operation will overflow + const DIV: i32 = (1/0) + T::DIV; + //~^ ERROR operation will panic + const OOB: i32 = [1][1] + T::OOB; + //~^ ERROR operation will panic +} diff --git a/src/test/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs b/src/test/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs new file mode 100644 index 00000000000..5b7c7be42cf --- /dev/null +++ b/src/test/ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs @@ -0,0 +1,91 @@ +// build-pass +// +// (this is deliberately *not* check-pass; I have confirmed that the bug in +// question does not replicate when one uses `cargo check` alone.) + +pub enum Void {} + +enum UninhabitedUnivariant { + _Variant(Void), +} + +enum UninhabitedMultivariant2 { + _Variant(Void), + _Warriont(Void), +} + +enum UninhabitedMultivariant3 { + _Variant(Void), + _Warriont(Void), + _Worrynot(Void), +} + +#[repr(C)] +enum UninhabitedUnivariantC { + _Variant(Void), +} + +#[repr(i32)] +enum UninhabitedUnivariant32 { + _Variant(Void), +} + +fn main() { + let _seed: UninhabitedUnivariant = None.unwrap(); + match _seed { + UninhabitedUnivariant::_Variant(_x) => {} + } + + let _seed: UninhabitedMultivariant2 = None.unwrap(); + match _seed { + UninhabitedMultivariant2::_Variant(_x) => {} + UninhabitedMultivariant2::_Warriont(_x) => {} + } + + let _seed: UninhabitedMultivariant2 = None.unwrap(); + match _seed { + UninhabitedMultivariant2::_Variant(_x) => {} + _ => {} + } + + let _seed: UninhabitedMultivariant2 = None.unwrap(); + match _seed { + UninhabitedMultivariant2::_Warriont(_x) => {} + _ => {} + } + + let _seed: UninhabitedMultivariant3 = None.unwrap(); + match _seed { + UninhabitedMultivariant3::_Variant(_x) => {} + UninhabitedMultivariant3::_Warriont(_x) => {} + UninhabitedMultivariant3::_Worrynot(_x) => {} + } + + let _seed: UninhabitedMultivariant3 = None.unwrap(); + match _seed { + UninhabitedMultivariant3::_Variant(_x) => {} + _ => {} + } + + let _seed: UninhabitedMultivariant3 = None.unwrap(); + match _seed { + UninhabitedMultivariant3::_Warriont(_x) => {} + _ => {} + } + + let _seed: UninhabitedMultivariant3 = None.unwrap(); + match _seed { + UninhabitedMultivariant3::_Worrynot(_x) => {} + _ => {} + } + + let _seed: UninhabitedUnivariantC = None.unwrap(); + match _seed { + UninhabitedUnivariantC::_Variant(_x) => {} + } + + let _seed: UninhabitedUnivariant32 = None.unwrap(); + match _seed { + UninhabitedUnivariant32::_Variant(_x) => {} + } +} diff --git a/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs b/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs new file mode 100644 index 00000000000..98be8c345a9 --- /dev/null +++ b/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.rs @@ -0,0 +1,11 @@ +// This is a regression test for #69310, which was injected by #68118. +// The issue here was that as a performance optimization, +// we call the query `lit_to_const(input);`. +// However, the literal `input.lit` would not be of the type expected by `input.ty`. +// As a result, we immediately called `bug!(...)` instead of bubbling up the problem +// so that it could be handled by the caller of `lit_to_const` (`ast_const_to_const`). + +fn main() {} + +const A: [(); 0.1] = [()]; //~ ERROR mismatched types +const B: [(); b"a"] = [()]; //~ ERROR mismatched types diff --git a/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.stderr b/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.stderr new file mode 100644 index 00000000000..7078b4bd7be --- /dev/null +++ b/src/test/ui/consts/issue-69310-array-size-lit-wrong-ty.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-69310-array-size-lit-wrong-ty.rs:10:15 + | +LL | const A: [(); 0.1] = [()]; + | ^^^ expected `usize`, found floating-point number + +error[E0308]: mismatched types + --> $DIR/issue-69310-array-size-lit-wrong-ty.rs:11:15 + | +LL | const B: [(); b"a"] = [()]; + | ^^^^ expected `usize`, found `&[u8; 1]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/consts/issue-69312.rs b/src/test/ui/consts/issue-69312.rs new file mode 100644 index 00000000000..413c6752079 --- /dev/null +++ b/src/test/ui/consts/issue-69312.rs @@ -0,0 +1,10 @@ +// build-pass + +// Verify that the compiler doesn't ICE during const prop while evaluating the index operation. + +#![allow(unconditional_panic)] + +fn main() { + let cols = [0u32; 0]; + cols[0]; +} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr index c8d060f5cdc..7794cc7583d 100644 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr @@ -4,7 +4,6 @@ error[E0658]: internal implementation detail LL | #[rustc_allow_const_fn_ptr] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index c3436d4840a..557439f3949 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -123,12 +123,9 @@ impl Foo { } struct AlanTuring(T); -const fn no_rpit2() -> AlanTuring { AlanTuring(0) } -//~^ ERROR `impl Trait` in const fn is unstable const fn no_apit2(_x: AlanTuring) {} //~^ ERROR trait bounds other than `Sized` const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` -const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~^ ERROR trait bounds other than `Sized` diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index 927cdfae189..512b343011b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -214,17 +214,8 @@ LL | impl Foo { = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: `impl Trait` in const fn is unstable - --> $DIR/min_const_fn.rs:126:24 - | -LL | const fn no_rpit2() -> AlanTuring { AlanTuring(0) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:128:34 + --> $DIR/min_const_fn.rs:126:34 | LL | const fn no_apit2(_x: AlanTuring) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +224,7 @@ LL | const fn no_apit2(_x: AlanTuring) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:130:22 + --> $DIR/min_const_fn.rs:128:22 | LL | const fn no_apit(_x: impl std::fmt::Debug) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -241,17 +232,8 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {} = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: `impl Trait` in const fn is unstable - --> $DIR/min_const_fn.rs:131:23 - | -LL | const fn no_rpit() -> impl std::fmt::Debug {} - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:132:23 + --> $DIR/min_const_fn.rs:129:23 | LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} | ^^ @@ -260,7 +242,7 @@ LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:133:32 + --> $DIR/min_const_fn.rs:130:32 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -269,7 +251,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:138:41 + --> $DIR/min_const_fn.rs:135:41 | LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -278,7 +260,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:141:21 + --> $DIR/min_const_fn.rs:138:21 | LL | const fn no_fn_ptrs(_x: fn()) {} | ^^ @@ -287,7 +269,7 @@ LL | const fn no_fn_ptrs(_x: fn()) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:143:27 + --> $DIR/min_const_fn.rs:140:27 | LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } | ^^^^ @@ -295,7 +277,7 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error: aborting due to 34 previous errors +error: aborting due to 32 previous errors Some errors have detailed explanations: E0493, E0723. For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs new file mode 100644 index 00000000000..9cc9b69ac0b --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs @@ -0,0 +1,9 @@ +struct AlanTuring(T); +const fn no_rpit2() -> AlanTuring { + //~^ ERROR `impl Trait` in const fn is unstable + AlanTuring(0) +} + +const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr new file mode 100644 index 00000000000..a62a340332d --- /dev/null +++ b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr @@ -0,0 +1,21 @@ +error[E0723]: `impl Trait` in const fn is unstable + --> $DIR/min_const_fn_impl_trait.rs:2:24 + | +LL | const fn no_rpit2() -> AlanTuring { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error[E0723]: `impl Trait` in const fn is unstable + --> $DIR/min_const_fn_impl_trait.rs:7:23 + | +LL | const fn no_rpit() -> impl std::fmt::Debug {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr index da00c49963e..c7e902132e9 100644 --- a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -16,7 +16,7 @@ error: any use of this value will cause an error LL | my_fn(); | ^^^^^^^ | | - | tried to call a function with ABI C using caller ABI Rust + | calling a function with ABI C using caller ABI Rust | inside call to `call_rust_fn` at $DIR/abi-mismatch.rs:13:17 ... LL | const VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern "C" fn()) }); diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr index 15e13942481..ad777cfe8ea 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -48,7 +48,7 @@ LL | | static FOO: AtomicUsize = AtomicUsize::new(0); LL | | unsafe { &*(&FOO as *const _ as *const usize) } LL | | LL | | }; - | |__^ constant accesses static + | |__^ type validation failed: encountered a reference pointing to a static variable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -97,7 +97,7 @@ LL | | static FOO: usize = 0; LL | | &FOO LL | | LL | | }; - | |__^ constant accesses static + | |__^ type validation failed: encountered a reference pointing to a static variable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/miri_unleashed/mutable_const.stderr b/src/test/ui/consts/miri_unleashed/mutable_const.stderr index 86f27784701..8456e8ec687 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_const.stderr @@ -11,7 +11,7 @@ LL | / const MUTATING_BEHIND_RAW: () = { LL | | // Test that `MUTABLE_BEHIND_RAW` is actually immutable, by doing this at const time. LL | | unsafe { LL | | *MUTABLE_BEHIND_RAW = 99 - | | ^^^^^^^^^^^^^^^^^^^^^^^^ tried to modify constant memory + | | ^^^^^^^^^^^^^^^^^^^^^^^^ writing to alloc1 which is read-only LL | | } LL | | }; | |__- diff --git a/src/test/ui/consts/miri_unleashed/mutable_const2.stderr b/src/test/ui/consts/miri_unleashed/mutable_const2.stderr index 3eb8e0ec182..dda9ddf1f48 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_const2.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_const2.stderr @@ -10,7 +10,7 @@ error: internal compiler error: mutable allocation in constant LL | const MUTABLE_BEHIND_RAW: *mut i32 = &UnsafeCell::new(42) as *const _ as *mut _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:355:17 +thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:360:17 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: internal compiler error: unexpected panic diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index 24da983cf08..21753074007 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -26,7 +26,7 @@ error: any use of this value will cause an error LL | intrinsics::ptr_offset_from(self, origin) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | a memory access tried to interpret some bytes as a pointer + | unable to turn bytes into a pointer | inside call to `std::ptr::const_ptr::::offset_from` at $DIR/offset_from_ub.rs:28:14 | ::: $DIR/offset_from_ub.rs:26:1 @@ -43,7 +43,7 @@ error: any use of this value will cause an error LL | intrinsics::ptr_offset_from(self, origin) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | exact_div: 1 cannot be divided by 2 without remainder + | exact_div: 1isize cannot be divided by 2isize without remainder | inside call to `std::ptr::const_ptr::::offset_from` at $DIR/offset_from_ub.rs:36:14 | ::: $DIR/offset_from_ub.rs:31:1 @@ -81,7 +81,7 @@ error: any use of this value will cause an error LL | intrinsics::ptr_offset_from(self, origin) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | a memory access tried to interpret some bytes as a pointer + | unable to turn bytes into a pointer | inside call to `std::ptr::const_ptr::::offset_from` at $DIR/offset_from_ub.rs:49:14 | ::: $DIR/offset_from_ub.rs:45:1 diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index fd68cb9c6cf..8836de0023c 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -8,8 +8,8 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | ^^^^^^^^^ associated item not found in `Foo` | = note: the method `HOST_SIZE` exists but the following trait bounds were not satisfied: - `A : std::marker::Sized` - `B : std::marker::Sized` + `A: std::marker::Sized` + `B: std::marker::Sized` error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/too_generic_eval_ice.rs:7:13 diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr index 296a55ef160..5a477714596 100644 --- a/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr +++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr @@ -21,7 +21,7 @@ LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^ | = note: source type: `usize` (word size) - = note: target type: `&'static [u8]` (2 * word size) + = note: target type: `&[u8]` (2 * word size) error: could not evaluate constant pattern --> $DIR/transmute-size-mismatch-before-typeck.rs:10:9 diff --git a/src/test/ui/consts/validate_never_arrays.stderr b/src/test/ui/consts/validate_never_arrays.stderr index cb995b8216f..77f0a2ebd40 100644 --- a/src/test/ui/consts/validate_never_arrays.stderr +++ b/src/test/ui/consts/validate_never_arrays.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:3:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at . + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .[0] | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -10,7 +10,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:6:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .[0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .[0] | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -18,7 +18,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/validate_never_arrays.rs:7:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .[0] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of the never type `!` at .[0] | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/definition-reachable/nested-fn.rs b/src/test/ui/definition-reachable/nested-fn.rs index b596ba8936a..b665b049f32 100644 --- a/src/test/ui/definition-reachable/nested-fn.rs +++ b/src/test/ui/definition-reachable/nested-fn.rs @@ -1,4 +1,4 @@ -// Check that functions visible to macros through paths with >2 segements are +// Check that functions visible to macros through paths with >2 segments are // considered reachable // aux-build:field-method-macro.rs diff --git a/src/test/ui/derives/derive-assoc-type-not-impl.stderr b/src/test/ui/derives/derive-assoc-type-not-impl.stderr index 2083a1d6522..c4c85773fbc 100644 --- a/src/test/ui/derives/derive-assoc-type-not-impl.stderr +++ b/src/test/ui/derives/derive-assoc-type-not-impl.stderr @@ -2,13 +2,20 @@ error[E0599]: no method named `clone` found for struct `Bar` in the cu --> $DIR/derive-assoc-type-not-impl.rs:18:30 | LL | struct Bar { - | ------------------ method `clone` not found for this + | ------------------ + | | + | method `clone` not found for this + | doesn't satisfy `Bar: std::clone::Clone` +... +LL | struct NotClone; + | ---------------- doesn't satisfy `NotClone: std::clone::Clone` ... LL | Bar:: { x: 1 }.clone(); | ^^^^^ method not found in `Bar` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `Bar : std::clone::Clone` + `NotClone: std::clone::Clone` + which is required by `Bar: std::clone::Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `std::clone::Clone` diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index f99bf2ffdc9..1382cf643a1 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -20,7 +20,7 @@ error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:32:10 | LL | let &&x = &1isize as &dyn T; - | ^^ + | ^^ ----------------- this expression has type `&dyn T` | | | expected trait object `dyn T`, found reference | help: you can probably remove the explicit borrow: `x` @@ -32,7 +32,7 @@ error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:36:11 | LL | let &&&x = &(&1isize as &dyn T); - | ^^ + | ^^ -------------------- this expression has type `&&dyn T` | | | expected trait object `dyn T`, found reference | help: you can probably remove the explicit borrow: `x` diff --git a/src/test/ui/destructuring-assignment/note-unsupported.stderr b/src/test/ui/destructuring-assignment/note-unsupported.stderr index a6805c32a6e..d4e25930d22 100644 --- a/src/test/ui/destructuring-assignment/note-unsupported.stderr +++ b/src/test/ui/destructuring-assignment/note-unsupported.stderr @@ -16,8 +16,6 @@ LL | (a, b) += (3, 4); | ------^^^^^^^^^^ | | | cannot use `+=` on type `({integer}, {integer})` - | - = note: an implementation of `std::ops::AddAssign` might be missing for `({integer}, {integer})` error[E0067]: invalid left-hand side of assignment --> $DIR/note-unsupported.rs:7:12 @@ -48,8 +46,6 @@ LL | [a, b] += [3, 4]; | ------^^^^^^^^^^ | | | cannot use `+=` on type `[{integer}; 2]` - | - = note: an implementation of `std::ops::AddAssign` might be missing for `[{integer}; 2]` error[E0067]: invalid left-hand side of assignment --> $DIR/note-unsupported.rs:11:12 diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs index fccfb7911ce..00845a17b11 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.rs +++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs @@ -45,4 +45,8 @@ type I = ty!()::AssocTy; //~^ ERROR missing angle brackets in associated item path //~| ERROR ambiguous associated type +trait K {} +fn foo>(x: X) {} +//~^ ERROR the type placeholder `_` is not allowed within types on item signatures + fn main() {} diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr index 64e49934d87..6d5f3d9f143 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr @@ -122,7 +122,15 @@ error[E0223]: ambiguous associated type LL | type I = ty!()::AssocTy; | ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::AssocTy` -error: aborting due to 19 previous errors +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/bad-assoc-ty.rs:49:13 + | +LL | fn foo>(x: X) {} + | ^ ^ not allowed in type signatures + | | + | not allowed in type signatures + +error: aborting due to 20 previous errors Some errors have detailed explanations: E0121, E0223. For more information about an error, try `rustc --explain E0121`. diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs index 60633c6930c..74f304d81a0 100644 --- a/src/test/ui/did_you_mean/issue-40006.rs +++ b/src/test/ui/did_you_mean/issue-40006.rs @@ -1,28 +1,28 @@ -impl dyn A { //~ ERROR missing +impl dyn A { Y -} +} //~ ERROR expected one of `!` or `::`, found `}` struct S; -trait X { //~ ERROR missing - X() {} +trait X { + X() {} //~ ERROR expected one of `!` or `::`, found `(` fn xxx() { ### } L = M; Z = { 2 + 3 }; ::Y (); } -trait A { //~ ERROR missing - X() {} +trait A { + X() {} //~ ERROR expected one of `!` or `::`, found `(` } trait B { fn xxx() { ### } //~ ERROR expected } -trait C { //~ ERROR missing `fn`, `type`, or `const` for associated-item declaration - L = M; +trait C { + L = M; //~ ERROR expected one of `!` or `::`, found `=` } -trait D { //~ ERROR missing `fn`, `type`, or `const` for associated-item declaration - Z = { 2 + 3 }; +trait D { + Z = { 2 + 3 }; //~ ERROR expected one of `!` or `::`, found `=` } trait E { ::Y (); //~ ERROR expected one of diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 072e61f6a3c..76e87a3749c 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -1,60 +1,88 @@ -error: missing `fn`, `type`, or `const` for associated-item declaration - --> $DIR/issue-40006.rs:1:13 +error: expected one of `!` or `::`, found `}` + --> $DIR/issue-40006.rs:3:1 | -LL | impl dyn A { - | _____________^ -LL | | Y - | |____^ missing `fn`, `type`, or `const` +LL | impl dyn A { + | - while parsing this item list starting here +LL | Y + | - expected one of `!` or `::` +LL | } + | ^ + | | + | unexpected token + | the item list ends here -error: missing `fn`, `type`, or `const` for associated-item declaration - --> $DIR/issue-40006.rs:7:10 +error: expected one of `!` or `::`, found `(` + --> $DIR/issue-40006.rs:8:6 | -LL | trait X { - | __________^ -LL | | X() {} - | |____^ missing `fn`, `type`, or `const` +LL | trait X { + | - while parsing this item list starting here +LL | X() {} + | ^ expected one of `!` or `::` +... +LL | } + | - the item list ends here -error: missing `fn`, `type`, or `const` for associated-item declaration - --> $DIR/issue-40006.rs:15:10 +error: expected one of `!` or `::`, found `(` + --> $DIR/issue-40006.rs:16:6 | -LL | trait A { - | __________^ -LL | | X() {} - | |____^ missing `fn`, `type`, or `const` +LL | trait A { + | - while parsing this item list starting here +LL | X() {} + | ^ expected one of `!` or `::` +LL | } + | - the item list ends here -error: expected `[`, found `#` +error: expected one of `!` or `[`, found `#` --> $DIR/issue-40006.rs:19:17 | LL | fn xxx() { ### } - | ^ expected `[` + | ^ expected one of `!` or `[` -error: missing `fn`, `type`, or `const` for associated-item declaration - --> $DIR/issue-40006.rs:21:10 +error: expected one of `!` or `::`, found `=` + --> $DIR/issue-40006.rs:22:7 | -LL | trait C { - | __________^ -LL | | L = M; - | |____^ missing `fn`, `type`, or `const` +LL | trait C { + | - while parsing this item list starting here +LL | L = M; + | ^ expected one of `!` or `::` +LL | } + | - the item list ends here -error: missing `fn`, `type`, or `const` for associated-item declaration - --> $DIR/issue-40006.rs:24:10 +error: expected one of `!` or `::`, found `=` + --> $DIR/issue-40006.rs:25:7 | -LL | trait D { - | __________^ -LL | | Z = { 2 + 3 }; - | |____^ missing `fn`, `type`, or `const` +LL | trait D { + | - while parsing this item list starting here +LL | Z = { 2 + 3 }; + | ^ expected one of `!` or `::` +LL | } + | - the item list ends here error: expected one of `!` or `::`, found `(` --> $DIR/issue-40006.rs:28:9 | +LL | trait E { + | - while parsing this item list starting here LL | ::Y (); | ^ expected one of `!` or `::` +LL | } + | - the item list ends here -error: missing `fn`, `type`, or `const` for associated-item declaration +error: missing `fn` for method definition --> $DIR/issue-40006.rs:32:8 | +LL | impl S { + | - while parsing this item list starting here LL | pub hello_method(&self) { - | ^ missing `fn`, `type`, or `const` + | ^ +... +LL | } + | - the item list ends here + | +help: add `fn` here to parse `hello_method` as a public method + | +LL | pub fn hello_method(&self) { + | ^^ error[E0599]: no method named `hello_method` found for struct `S` in the current scope --> $DIR/issue-40006.rs:38:7 diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.rs b/src/test/ui/directory_ownership/macro-expanded-mod.rs index 9752a64162e..9cb159603a8 100644 --- a/src/test/ui/directory_ownership/macro-expanded-mod.rs +++ b/src/test/ui/directory_ownership/macro-expanded-mod.rs @@ -1,7 +1,9 @@ // Test that macro-expanded non-inline modules behave correctly macro_rules! mod_decl { - ($i:ident) => { mod $i; } + ($i:ident) => { + mod $i; //~ ERROR Cannot declare a non-inline module inside a block + }; } mod macro_expanded_mod_helper { @@ -10,5 +12,4 @@ mod macro_expanded_mod_helper { fn main() { mod_decl!(foo); - //~^ ERROR Cannot declare a non-inline module inside a block } diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.stderr b/src/test/ui/directory_ownership/macro-expanded-mod.stderr index 620a00f89bb..f90419247c9 100644 --- a/src/test/ui/directory_ownership/macro-expanded-mod.stderr +++ b/src/test/ui/directory_ownership/macro-expanded-mod.stderr @@ -1,8 +1,13 @@ error: Cannot declare a non-inline module inside a block unless it has a path attribute - --> $DIR/macro-expanded-mod.rs:12:15 + --> $DIR/macro-expanded-mod.rs:5:9 | +LL | mod $i; + | ^^^^^^^ +... LL | mod_decl!(foo); - | ^^^ + | --------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr b/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr index 46acc7e66d8..d034942ca5d 100644 --- a/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr +++ b/src/test/ui/directory_ownership/non-inline-mod-restriction.stderr @@ -1,8 +1,8 @@ error: Cannot declare a non-inline module inside a block unless it has a path attribute - --> $DIR/non-inline-mod-restriction.rs:4:9 + --> $DIR/non-inline-mod-restriction.rs:4:5 | LL | mod foo; - | ^^^ + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index 451686d9ae2..d31736f142c 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -3,6 +3,7 @@ #![feature(generators, generator_trait, untagged_unions)] #![feature(move_ref_pattern)] +#![feature(bindings_after_at)] #![allow(unused_assignments)] #![allow(unused_variables)] @@ -291,6 +292,44 @@ fn subslice_mixed_min_lengths(a: &Allocator, c: i32) { } } +fn bindings_after_at_dynamic_init_move(a: &Allocator, c: bool) { + let foo = if c { Some(a.alloc()) } else { None }; + let _x; + + if let bar @ Some(_) = foo { + _x = bar; + } +} + +fn bindings_after_at_dynamic_init_ref(a: &Allocator, c: bool) { + let foo = if c { Some(a.alloc()) } else { None }; + let _x; + + if let bar @ Some(_baz) = &foo { + _x = bar; + } +} + +fn bindings_after_at_dynamic_drop_move(a: &Allocator, c: bool) { + let foo = if c { Some(a.alloc()) } else { None }; + + if let bar @ Some(_) = foo { + bar + } else { + None + }; +} + +fn bindings_after_at_dynamic_drop_ref(a: &Allocator, c: bool) { + let foo = if c { Some(a.alloc()) } else { None }; + + if let bar @ Some(_baz) = &foo { + bar + } else { + &None + }; +} + fn move_ref_pattern(a: &Allocator) { let mut tup = (a.alloc(), a.alloc(), a.alloc(), a.alloc()); let (ref _a, ref mut _b, _c, mut _d) = tup; @@ -471,5 +510,14 @@ fn main() { run_test(|a| panic_after_init_temp(a)); run_test(|a| panic_after_init_by_loop(a)); + run_test(|a| bindings_after_at_dynamic_init_move(a, true)); + run_test(|a| bindings_after_at_dynamic_init_move(a, false)); + run_test(|a| bindings_after_at_dynamic_init_ref(a, true)); + run_test(|a| bindings_after_at_dynamic_init_ref(a, false)); + run_test(|a| bindings_after_at_dynamic_drop_move(a, true)); + run_test(|a| bindings_after_at_dynamic_drop_move(a, false)); + run_test(|a| bindings_after_at_dynamic_drop_ref(a, true)); + run_test(|a| bindings_after_at_dynamic_drop_ref(a, false)); + run_test_nopanic(|a| union1(a)); } diff --git a/src/test/ui/duplicate/dupe-symbols-7.rs b/src/test/ui/duplicate/dupe-symbols-7.rs index 89a32c61620..633ca4c3189 100644 --- a/src/test/ui/duplicate/dupe-symbols-7.rs +++ b/src/test/ui/duplicate/dupe-symbols-7.rs @@ -1,7 +1,7 @@ // build-fail // -// error-pattern: entry symbol `main` defined multiple times +// error-pattern: entry symbol `main` declared multiple times // FIXME https://github.com/rust-lang/rust/issues/59774 // normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" diff --git a/src/test/ui/duplicate/dupe-symbols-7.stderr b/src/test/ui/duplicate/dupe-symbols-7.stderr index 608ae27110a..2ea5521e095 100644 --- a/src/test/ui/duplicate/dupe-symbols-7.stderr +++ b/src/test/ui/duplicate/dupe-symbols-7.stderr @@ -1,4 +1,4 @@ -error: entry symbol `main` defined multiple times +error: entry symbol `main` declared multiple times --> $DIR/dupe-symbols-7.rs:12:1 | LL | fn main(){} diff --git a/src/test/ui/duplicate/dupe-symbols-8.rs b/src/test/ui/duplicate/dupe-symbols-8.rs new file mode 100644 index 00000000000..ce7fa24a9fe --- /dev/null +++ b/src/test/ui/duplicate/dupe-symbols-8.rs @@ -0,0 +1,12 @@ +// build-fail +// error-pattern: entry symbol `main` declared multiple times +// +// See #67946. + +#![allow(warnings)] +fn main() { + extern "Rust" { + fn main(); + } + unsafe { main(); } +} diff --git a/src/test/ui/duplicate/dupe-symbols-8.stderr b/src/test/ui/duplicate/dupe-symbols-8.stderr new file mode 100644 index 00000000000..f001201b8d0 --- /dev/null +++ b/src/test/ui/duplicate/dupe-symbols-8.stderr @@ -0,0 +1,15 @@ +error: entry symbol `main` declared multiple times + --> $DIR/dupe-symbols-8.rs:7:1 + | +LL | / fn main() { +LL | | extern "Rust" { +LL | | fn main(); +LL | | } +LL | | unsafe { main(); } +LL | | } + | |_^ + | + = help: did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead + +error: aborting due to previous error + diff --git a/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr b/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr index f44f81fce71..88a1f5dc673 100644 --- a/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr +++ b/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr @@ -7,8 +7,8 @@ LL | produces_async! {} = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: you can escape reserved keywords to use them as identifiers | -LL | () => (pub fn r#async () { }) - | ^^^^^^^ +LL | () => (pub fn r#async() {}) + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr b/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr index 22a7495ca23..e12d1a48463 100644 --- a/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -33,10 +33,10 @@ LL | r#async = consumes_async_raw!(async); | ^^^^^ no rules expected this token in macro call error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` - --> <::edition_kw_macro_2015::passes_ident macros>:1:22 + --> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23 | -LL | ($ i : ident) => ($ i) - | ^ expected one of `move`, `|`, or `||` +LL | ($i: ident) => ($i) + | ^ expected one of `move`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2015-parsing.rs:16:8 | diff --git a/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr b/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr index a8fc58fc0cb..5eaa1d03a4a 100644 --- a/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr @@ -7,8 +7,8 @@ LL | produces_async! {} = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: you can escape reserved keywords to use them as identifiers | -LL | () => (pub fn r#async () { }) - | ^^^^^^^ +LL | () => (pub fn r#async() {}) + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr b/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr index 7488fcc2e58..110165fc077 100644 --- a/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -33,10 +33,10 @@ LL | r#async = consumes_async_raw!(async); | ^^^^^ no rules expected this token in macro call error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` - --> <::edition_kw_macro_2018::passes_ident macros>:1:22 + --> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23 | -LL | ($ i : ident) => ($ i) - | ^ expected one of `move`, `|`, or `||` +LL | ($i: ident) => ($i) + | ^ expected one of `move`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2018-parsing.rs:16:8 | diff --git a/src/test/ui/elide-errors-on-mismatched-tuple.stderr b/src/test/ui/elide-errors-on-mismatched-tuple.stderr index 122c71bebc4..e0537ff6faa 100644 --- a/src/test/ui/elide-errors-on-mismatched-tuple.stderr +++ b/src/test/ui/elide-errors-on-mismatched-tuple.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/elide-errors-on-mismatched-tuple.rs:14:9 | LL | let (a, b, c) = (A::new(), A::new()); // This tuple is 2 elements, should be three - | ^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements + | ^^^^^^^^^ -------------------- this expression has type `(A, A)` + | | + | expected a tuple with 2 elements, found one with 3 elements | = note: expected tuple `(A, A)` found tuple `(_, _, _)` diff --git a/src/test/ui/enum/enum-discrim-too-small2.stderr b/src/test/ui/enum/enum-discrim-too-small2.stderr index 3aa88df29f1..fadf6ab86b4 100644 --- a/src/test/ui/enum/enum-discrim-too-small2.stderr +++ b/src/test/ui/enum/enum-discrim-too-small2.stderr @@ -9,24 +9,31 @@ note: the lint level is defined here | LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ + = note: the literal `223` does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i16` --> $DIR/enum-discrim-too-small2.rs:15:12 | LL | Ci16 = 55555, | ^^^^^ + | + = note: the literal `55555` does not fit into the type `i16` whose range is `-32768..=32767` error: literal out of range for `i32` --> $DIR/enum-discrim-too-small2.rs:22:12 | LL | Ci32 = 3_000_000_000, | ^^^^^^^^^^^^^ + | + = note: the literal `3_000_000_000` does not fit into the type `i32` whose range is `-2147483648..=2147483647` error: literal out of range for `i64` --> $DIR/enum-discrim-too-small2.rs:29:12 | LL | Ci64 = 9223372036854775809, | ^^^^^^^^^^^^^^^^^^^ + | + = note: the literal `9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` error: aborting due to 4 previous errors diff --git a/src/test/ui/error-codes/E0057.stderr b/src/test/ui/error-codes/E0057.stderr index 6b5890cac36..31579e28289 100644 --- a/src/test/ui/error-codes/E0057.stderr +++ b/src/test/ui/error-codes/E0057.stderr @@ -1,14 +1,18 @@ -error[E0057]: this function takes 1 parameter but 0 parameters were supplied +error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/E0057.rs:3:13 | LL | let a = f(); - | ^^^ expected 1 parameter + | ^-- supplied 0 arguments + | | + | expected 1 argument -error[E0057]: this function takes 1 parameter but 2 parameters were supplied +error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/E0057.rs:5:13 | LL | let c = f(2, 3); - | ^^^^^^^ expected 1 parameter + | ^ - - supplied 2 arguments + | | + | expected 1 argument error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0060.rs b/src/test/ui/error-codes/E0060.rs index 2bb490fb3ea..941eb2a210b 100644 --- a/src/test/ui/error-codes/E0060.rs +++ b/src/test/ui/error-codes/E0060.rs @@ -5,5 +5,5 @@ extern "C" { fn main() { unsafe { printf(); } //~^ ERROR E0060 - //~| expected at least 1 parameter + //~| expected at least 1 argument } diff --git a/src/test/ui/error-codes/E0060.stderr b/src/test/ui/error-codes/E0060.stderr index 8a2e7d1a72c..a600592c6c2 100644 --- a/src/test/ui/error-codes/E0060.stderr +++ b/src/test/ui/error-codes/E0060.stderr @@ -1,11 +1,13 @@ -error[E0060]: this function takes at least 1 parameter but 0 parameters were supplied +error[E0060]: this function takes at least 1 argument but 0 arguments were supplied --> $DIR/E0060.rs:6:14 | LL | fn printf(_: *const u8, ...) -> u32; | ------------------------------------ defined here ... LL | unsafe { printf(); } - | ^^^^^^^^ expected at least 1 parameter + | ^^^^^^-- supplied 0 arguments + | | + | expected at least 1 argument error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0061.rs b/src/test/ui/error-codes/E0061.rs index e64ea36ac92..c7b5fe4310e 100644 --- a/src/test/ui/error-codes/E0061.rs +++ b/src/test/ui/error-codes/E0061.rs @@ -5,9 +5,9 @@ fn f2(a: u16) {} fn main() { f(0); //~^ ERROR E0061 - //~| expected 2 parameters + //~| expected 2 arguments f2(); //~^ ERROR E0061 - //~| expected 1 parameter + //~| expected 1 argument } diff --git a/src/test/ui/error-codes/E0061.stderr b/src/test/ui/error-codes/E0061.stderr index 73103241f7a..dfefa0df313 100644 --- a/src/test/ui/error-codes/E0061.stderr +++ b/src/test/ui/error-codes/E0061.stderr @@ -1,20 +1,24 @@ -error[E0061]: this function takes 2 parameters but 1 parameter was supplied +error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/E0061.rs:6:5 | LL | fn f(a: u16, b: &str) {} | --------------------- defined here ... LL | f(0); - | ^^^^ expected 2 parameters + | ^ - supplied 1 argument + | | + | expected 2 arguments -error[E0061]: this function takes 1 parameter but 0 parameters were supplied +error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/E0061.rs:10:5 | LL | fn f2(a: u16) {} | ------------- defined here ... LL | f2(); - | ^^^^ expected 1 parameter + | ^^-- supplied 0 arguments + | | + | expected 1 argument error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0067.stderr b/src/test/ui/error-codes/E0067.stderr index 526503798b3..fad8270fd5a 100644 --- a/src/test/ui/error-codes/E0067.stderr +++ b/src/test/ui/error-codes/E0067.stderr @@ -5,8 +5,6 @@ LL | LinkedList::new() += 1; | -----------------^^^^^ | | | cannot use `+=` on type `std::collections::LinkedList<_>` - | - = note: an implementation of `std::ops::AddAssign` might be missing for `std::collections::LinkedList<_>` error[E0067]: invalid left-hand side of assignment --> $DIR/E0067.rs:4:23 diff --git a/src/test/ui/error-codes/E0121.stderr b/src/test/ui/error-codes/E0121.stderr index 5a5c6b40c5a..ad854837ae5 100644 --- a/src/test/ui/error-codes/E0121.stderr +++ b/src/test/ui/error-codes/E0121.stderr @@ -14,7 +14,7 @@ LL | static BAR: _ = "test"; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `&'static str` + | help: replace `_` with the correct type: `&str` error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0197.stderr b/src/test/ui/error-codes/E0197.stderr index 51ed9c83bc9..35e1042649e 100644 --- a/src/test/ui/error-codes/E0197.stderr +++ b/src/test/ui/error-codes/E0197.stderr @@ -1,8 +1,8 @@ error[E0197]: inherent impls cannot be unsafe - --> $DIR/E0197.rs:3:1 + --> $DIR/E0197.rs:3:13 | LL | unsafe impl Foo { } - | ------^^^^^^^^^^^^^ + | ------ ^^^ inherent impl for this type | | | unsafe because of this diff --git a/src/test/ui/error-codes/E0198.stderr b/src/test/ui/error-codes/E0198.stderr index 90e8b4abd12..bb2efefb427 100644 --- a/src/test/ui/error-codes/E0198.stderr +++ b/src/test/ui/error-codes/E0198.stderr @@ -1,9 +1,10 @@ error[E0198]: negative impls cannot be unsafe - --> $DIR/E0198.rs:5:1 + --> $DIR/E0198.rs:5:13 | LL | unsafe impl !Send for Foo { } - | ------^^^^^^^^^^^^^^^^^^^^^^^ - | | + | ------ -^^^^ + | | | + | | negative because of this | unsafe because of this error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0396-fixed.stderr b/src/test/ui/error-codes/E0396-fixed.stderr index 7222f87da24..68505552562 100644 --- a/src/test/ui/error-codes/E0396-fixed.stderr +++ b/src/test/ui/error-codes/E0396-fixed.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const VALUE: u8 = unsafe { *REG_ADDR }; | ---------------------------^^^^^^^^^--- | | - | a memory access tried to interpret some bytes as a pointer + | unable to turn bytes into a pointer | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/error-codes/E0583.stderr b/src/test/ui/error-codes/E0583.stderr index ef7a48bc8a4..dbe70035595 100644 --- a/src/test/ui/error-codes/E0583.stderr +++ b/src/test/ui/error-codes/E0583.stderr @@ -1,10 +1,10 @@ error[E0583]: file not found for module `module_that_doesnt_exist` - --> $DIR/E0583.rs:1:5 + --> $DIR/E0583.rs:1:1 | LL | mod module_that_doesnt_exist; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: name the file either module_that_doesnt_exist.rs or module_that_doesnt_exist/mod.rs inside the directory "$DIR" + = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs" error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0624.rs b/src/test/ui/error-codes/E0624.rs index 45f72a565ca..4c68b70fb16 100644 --- a/src/test/ui/error-codes/E0624.rs +++ b/src/test/ui/error-codes/E0624.rs @@ -8,5 +8,5 @@ mod inner { fn main() { let foo = inner::Foo; - foo.method(); //~ ERROR method `method` is private [E0624] + foo.method(); //~ ERROR associated function `method` is private [E0624] } diff --git a/src/test/ui/error-codes/E0624.stderr b/src/test/ui/error-codes/E0624.stderr index 01ac24cfbbe..65256c8dd2d 100644 --- a/src/test/ui/error-codes/E0624.stderr +++ b/src/test/ui/error-codes/E0624.stderr @@ -1,4 +1,4 @@ -error[E0624]: method `method` is private +error[E0624]: associated function `method` is private --> $DIR/E0624.rs:11:9 | LL | foo.method(); diff --git a/src/test/ui/error-codes/E0719.stderr b/src/test/ui/error-codes/E0719.stderr index a046fbfc3d0..0e4bbf083ba 100644 --- a/src/test/ui/error-codes/E0719.stderr +++ b/src/test/ui/error-codes/E0719.stderr @@ -16,3 +16,4 @@ LL | fn test() -> Box> { error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0719`. diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index 9b69b373364..fb5290bf64e 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -23,8 +23,6 @@ LL | x += 2; | -^^^^^ | | | cannot use `+=` on type `&str` - | - = note: an implementation of `std::ops::AddAssign` might be missing for `&str` error[E0599]: no method named `z` found for reference `&str` in the current scope --> $DIR/error-festival.rs:16:7 diff --git a/src/test/ui/explain.stdout b/src/test/ui/explain.stdout index 9ea56271f59..c50c46ee564 100644 --- a/src/test/ui/explain.stdout +++ b/src/test/ui/explain.stdout @@ -46,7 +46,7 @@ This pattern should be rewritten. There are a few possible ways to do this: - change the original fn declaration to match the expected signature, and do the cast in the fn body (the preferred option) -- cast the fn item fo a fn pointer before calling transmute, as shown here: +- cast the fn item of a fn pointer before calling transmute, as shown here: ``` let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_)); diff --git a/src/test/ui/explore-issue-38412.stderr b/src/test/ui/explore-issue-38412.stderr index 4c80989951a..94a2cfe013d 100644 --- a/src/test/ui/explore-issue-38412.stderr +++ b/src/test/ui/explore-issue-38412.stderr @@ -79,19 +79,19 @@ LL | r.unstable_undeclared(); = note: see issue #38412 for more information = help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable -error[E0624]: method `pub_crate` is private +error[E0624]: associated function `pub_crate` is private --> $DIR/explore-issue-38412.rs:50:7 | LL | r.pub_crate(); | ^^^^^^^^^ -error[E0624]: method `pub_mod` is private +error[E0624]: associated function `pub_mod` is private --> $DIR/explore-issue-38412.rs:51:7 | LL | r.pub_mod(); | ^^^^^^^ -error[E0624]: method `private` is private +error[E0624]: associated function `private` is private --> $DIR/explore-issue-38412.rs:52:7 | LL | r.private(); @@ -115,19 +115,19 @@ LL | t.unstable_undeclared(); = note: see issue #38412 for more information = help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable -error[E0624]: method `pub_crate` is private +error[E0624]: associated function `pub_crate` is private --> $DIR/explore-issue-38412.rs:63:7 | LL | t.pub_crate(); | ^^^^^^^^^ -error[E0624]: method `pub_mod` is private +error[E0624]: associated function `pub_mod` is private --> $DIR/explore-issue-38412.rs:64:7 | LL | t.pub_mod(); | ^^^^^^^ -error[E0624]: method `private` is private +error[E0624]: associated function `private` is private --> $DIR/explore-issue-38412.rs:65:7 | LL | t.private(); diff --git a/src/test/ui/extern/extern-const.stderr b/src/test/ui/extern/extern-const.stderr index 258202b6903..7f67adbdb19 100644 --- a/src/test/ui/extern/extern-const.stderr +++ b/src/test/ui/extern/extern-const.stderr @@ -1,8 +1,12 @@ error: extern items cannot be `const` - --> $DIR/extern-const.rs:16:5 + --> $DIR/extern-const.rs:16:11 | LL | const rust_dbg_static_mut: libc::c_int; - | ^^^^^ help: try using a static value: `static` + | ------^^^^^^^^^^^^^^^^^^^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs b/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs deleted file mode 100644 index 452b45b3445..00000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[doc(spotlight)] //~ ERROR: `#[doc(spotlight)]` is experimental -trait SomeTrait {} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr deleted file mode 100644 index 010d74054a4..00000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: `#[doc(spotlight)]` is experimental - --> $DIR/feature-gate-doc_spotlight.rs:1:1 - | -LL | #[doc(spotlight)] - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #45040 for more information - = help: add `#![feature(doc_spotlight)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr index 689a3757343..fbc4e8abc42 100644 --- a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr +++ b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr @@ -2,7 +2,7 @@ error[E0310]: the parameter type `U` may not live long enough --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:5 | LL | struct Foo { - | - help: consider adding an explicit lifetime bound `U: 'static`... + | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | bar: Bar | ^^^^^^^^^^^ | diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.rs b/src/test/ui/feature-gates/feature-gate-member-constraints.rs index 293a93352e6..f6a92b0d0bf 100644 --- a/src/test/ui/feature-gates/feature-gate-member-constraints.rs +++ b/src/test/ui/feature-gates/feature-gate-member-constraints.rs @@ -1,9 +1,10 @@ -trait Trait<'a, 'b> { } +trait Trait<'a, 'b> {} impl Trait<'_, '_> for T {} fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { //~^ ERROR ambiguous lifetime bound + //~| ERROR ambiguous lifetime bound (x, y) } -fn main() { } +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr index 3745d5e1c59..c2ec7ae16a3 100644 --- a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr +++ b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr @@ -6,5 +6,13 @@ LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { | = help: add #![feature(member_constraints)] to the crate attributes to enable -error: aborting due to previous error +error: ambiguous lifetime bound in `impl Trait` + --> $DIR/feature-gate-member-constraints.rs:4:43 + | +LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { + | ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another + | + = help: add #![feature(member_constraints)] to the crate attributes to enable + +error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-no-debug-2.rs b/src/test/ui/feature-gates/feature-gate-no-debug-2.rs deleted file mode 100644 index b399bd2cc0f..00000000000 --- a/src/test/ui/feature-gates/feature-gate-no-debug-2.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![deny(deprecated)] -#![feature(no_debug)] - -#[no_debug] //~ ERROR use of deprecated attribute `no_debug` -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-no-debug-2.stderr b/src/test/ui/feature-gates/feature-gate-no-debug-2.stderr deleted file mode 100644 index 9a6f898f2a5..00000000000 --- a/src/test/ui/feature-gates/feature-gate-no-debug-2.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721 - --> $DIR/feature-gate-no-debug-2.rs:4:1 - | -LL | #[no_debug] - | ^^^^^^^^^^^ help: remove this attribute - | -note: the lint level is defined here - --> $DIR/feature-gate-no-debug-2.rs:1:9 - | -LL | #![deny(deprecated)] - | ^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/feature-gates/feature-gate-no-debug.rs b/src/test/ui/feature-gates/feature-gate-no-debug.rs deleted file mode 100644 index a472c4c7663..00000000000 --- a/src/test/ui/feature-gates/feature-gate-no-debug.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![allow(deprecated)] - -#[no_debug] //~ ERROR the `#[no_debug]` attribute was -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-no-debug.stderr b/src/test/ui/feature-gates/feature-gate-no-debug.stderr deleted file mode 100644 index e146d643bcb..00000000000 --- a/src/test/ui/feature-gates/feature-gate-no-debug.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand - --> $DIR/feature-gate-no-debug.rs:3:1 - | -LL | #[no_debug] - | ^^^^^^^^^^^ - | - = note: see issue #29721 for more information - = help: add `#![feature(no_debug)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr b/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr index d29c373a33c..490d29ad8a3 100644 --- a/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr +++ b/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr @@ -8,10 +8,10 @@ LL | auto trait AutoDummyTrait {} = help: add `#![feature(optin_builtin_traits)]` to the crate attributes to enable error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now - --> $DIR/feature-gate-optin-builtin-traits.rs:9:1 + --> $DIR/feature-gate-optin-builtin-traits.rs:9:6 | LL | impl !AutoDummyTrait for DummyStruct {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: see issue #13231 for more information = help: add `#![feature(optin_builtin_traits)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr index 082d897c01d..82dec1fd4cf 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr @@ -4,7 +4,6 @@ error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit test LL | #[rustc_variance] | ^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable @@ -13,7 +12,6 @@ error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests a LL | #[rustc_error] | ^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable niche optimizations in libcore and will never be stable @@ -22,7 +20,6 @@ error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just u LL | #[rustc_nonnull_optimization_guaranteed] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr index 58f8b4e7035..1e039f17a0d 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr @@ -4,7 +4,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[rustc::unknown] | ^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: expected attribute, found macro `rustc::unknown` @@ -19,7 +18,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[unknown::rustc] | ^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: expected attribute, found macro `unknown::rustc` @@ -34,7 +32,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[rustc_unknown] | ^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: cannot find attribute `rustc_unknown` in this scope @@ -49,7 +46,6 @@ error[E0658]: the `#[rustc_dummy]` attribute is just used for rustc unit tests a LL | #[rustc_dummy] | ^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: aborting due to 7 previous errors diff --git a/src/test/ui/fmt/send-sync.stderr b/src/test/ui/fmt/send-sync.stderr index be6e41afaf8..c8439764eff 100644 --- a/src/test/ui/fmt/send-sync.stderr +++ b/src/test/ui/fmt/send-sync.stderr @@ -1,34 +1,30 @@ -error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely +error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely --> $DIR/send-sync.rs:8:5 | LL | fn send(_: T) {} | ---- ---- required by this bound in `send` ... LL | send(format_args!("{:?}", c)); - | ^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely + | ^^^^ `core::fmt::Opaque` cannot be shared between threads safely | - = help: within `[std::fmt::ArgumentV1<'_>]`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)` - = note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>` - = note: required because it appears within the type `core::fmt::Void` - = note: required because it appears within the type `&core::fmt::Void` + = help: within `[std::fmt::ArgumentV1<'_>]`, the trait `std::marker::Sync` is not implemented for `core::fmt::Opaque` + = note: required because it appears within the type `&core::fmt::Opaque` = note: required because it appears within the type `std::fmt::ArgumentV1<'_>` = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` = note: required because of the requirements on the impl of `std::marker::Send` for `&[std::fmt::ArgumentV1<'_>]` = note: required because it appears within the type `std::fmt::Arguments<'_>` -error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely +error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely --> $DIR/send-sync.rs:9:5 | LL | fn sync(_: T) {} | ---- ---- required by this bound in `sync` ... LL | sync(format_args!("{:?}", c)); - | ^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely + | ^^^^ `core::fmt::Opaque` cannot be shared between threads safely | - = help: within `std::fmt::Arguments<'_>`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)` - = note: required because it appears within the type `std::marker::PhantomData<*mut (dyn std::ops::Fn() + 'static)>` - = note: required because it appears within the type `core::fmt::Void` - = note: required because it appears within the type `&core::fmt::Void` + = help: within `std::fmt::Arguments<'_>`, the trait `std::marker::Sync` is not implemented for `core::fmt::Opaque` + = note: required because it appears within the type `&core::fmt::Opaque` = note: required because it appears within the type `std::fmt::ArgumentV1<'_>` = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` = note: required because it appears within the type `&[std::fmt::ArgumentV1<'_>]` diff --git a/src/test/ui/fn-in-pat.rs b/src/test/ui/fn-in-pat.rs index b83252012b8..2d7c86b8666 100644 --- a/src/test/ui/fn-in-pat.rs +++ b/src/test/ui/fn-in-pat.rs @@ -8,7 +8,7 @@ fn hof(_: F) where F: FnMut(()) {} fn ice() { hof(|c| match c { - A::new() => (), //~ ERROR expected tuple struct or tuple variant, found method + A::new() => (), //~ ERROR expected tuple struct or tuple variant, found associated function _ => () }) } diff --git a/src/test/ui/fn-in-pat.stderr b/src/test/ui/fn-in-pat.stderr index 5d6632f2fc2..2482d632695 100644 --- a/src/test/ui/fn-in-pat.stderr +++ b/src/test/ui/fn-in-pat.stderr @@ -1,4 +1,4 @@ -error[E0164]: expected tuple struct or tuple variant, found method `A::new` +error[E0164]: expected tuple struct or tuple variant, found associated function `A::new` --> $DIR/fn-in-pat.rs:11:9 | LL | A::new() => (), diff --git a/src/test/ui/for/for-loop-type-error.stderr b/src/test/ui/for/for-loop-type-error.stderr index 0ed26384f40..c93a3b9b25c 100644 --- a/src/test/ui/for/for-loop-type-error.stderr +++ b/src/test/ui/for/for-loop-type-error.stderr @@ -5,8 +5,6 @@ LL | let x = () + (); | -- ^ -- () | | | () - | - = note: an implementation of `std::ops::Add` might be missing for `()` error: aborting due to previous error diff --git a/src/test/ui/generator/async-generator-issue-67158.rs b/src/test/ui/generator/async-generator-issue-67158.rs new file mode 100644 index 00000000000..8125a7a9bb6 --- /dev/null +++ b/src/test/ui/generator/async-generator-issue-67158.rs @@ -0,0 +1,6 @@ +#![feature(generators)] +// edition:2018 +// Regression test for #67158. +fn main() { + async { yield print!(":C") }; //~ ERROR `async` generators are not yet supported +} diff --git a/src/test/ui/generator/async-generator-issue-67158.stderr b/src/test/ui/generator/async-generator-issue-67158.stderr new file mode 100644 index 00000000000..7270d188e8b --- /dev/null +++ b/src/test/ui/generator/async-generator-issue-67158.stderr @@ -0,0 +1,9 @@ +error[E0727]: `async` generators are not yet supported + --> $DIR/async-generator-issue-67158.rs:5:13 + | +LL | async { yield print!(":C") }; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0727`. diff --git a/src/test/ui/generator/discriminant.rs b/src/test/ui/generator/discriminant.rs new file mode 100644 index 00000000000..8a0f8a380ab --- /dev/null +++ b/src/test/ui/generator/discriminant.rs @@ -0,0 +1,134 @@ +//! Tests that generator discriminant sizes and ranges are chosen optimally and that they are +//! reflected in the output of `mem::discriminant`. + +// run-pass + +#![feature(generators, generator_trait, core_intrinsics)] + +use std::intrinsics::discriminant_value; +use std::marker::Unpin; +use std::mem::size_of_val; +use std::{cmp, ops::*}; + +macro_rules! yield25 { + ($e:expr) => { + yield $e; + yield $e; + yield $e; + yield $e; + yield $e; + + yield $e; + yield $e; + yield $e; + yield $e; + yield $e; + + yield $e; + yield $e; + yield $e; + yield $e; + yield $e; + + yield $e; + yield $e; + yield $e; + yield $e; + yield $e; + + yield $e; + yield $e; + yield $e; + yield $e; + yield $e; + }; +} + +/// Yields 250 times. +macro_rules! yield250 { + () => { + yield250!(()) + }; + + ($e:expr) => { + yield25!($e); + yield25!($e); + yield25!($e); + yield25!($e); + yield25!($e); + + yield25!($e); + yield25!($e); + yield25!($e); + yield25!($e); + yield25!($e); + }; +} + +fn cycle(gen: impl Generator<()> + Unpin, expected_max_discr: u64) { + let mut gen = Box::pin(gen); + let mut max_discr = 0; + loop { + max_discr = cmp::max(max_discr, discriminant_value(gen.as_mut().get_mut())); + match gen.as_mut().resume(()) { + GeneratorState::Yielded(_) => {} + GeneratorState::Complete(_) => { + assert_eq!(max_discr, expected_max_discr); + return; + } + } + } +} + +fn main() { + // Has only one invalid discr. value. + let gen_u8_tiny_niche = || { + || { + // 3 reserved variants + + yield250!(); // 253 variants + + yield; // 254 + yield; // 255 + } + }; + + // Uses all values in the u8 discriminant. + let gen_u8_full = || { + || { + // 3 reserved variants + + yield250!(); // 253 variants + + yield; // 254 + yield; // 255 + yield; // 256 + } + }; + + // Barely needs a u16 discriminant. + let gen_u16 = || { + || { + // 3 reserved variants + + yield250!(); // 253 variants + + yield; // 254 + yield; // 255 + yield; // 256 + yield; // 257 + } + }; + + assert_eq!(size_of_val(&gen_u8_tiny_niche()), 1); + assert_eq!(size_of_val(&Some(gen_u8_tiny_niche())), 1); // uses niche + assert_eq!(size_of_val(&Some(Some(gen_u8_tiny_niche()))), 2); // cannot use niche anymore + assert_eq!(size_of_val(&gen_u8_full()), 1); + assert_eq!(size_of_val(&Some(gen_u8_full())), 2); // cannot use niche + assert_eq!(size_of_val(&gen_u16()), 2); + assert_eq!(size_of_val(&Some(gen_u16())), 2); // uses niche + + cycle(gen_u8_tiny_niche(), 254); + cycle(gen_u8_full(), 255); + cycle(gen_u16(), 256); +} diff --git a/src/test/ui/generator-yielding-or-returning-itself.rs b/src/test/ui/generator/generator-yielding-or-returning-itself.rs similarity index 100% rename from src/test/ui/generator-yielding-or-returning-itself.rs rename to src/test/ui/generator/generator-yielding-or-returning-itself.rs diff --git a/src/test/ui/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr similarity index 100% rename from src/test/ui/generator-yielding-or-returning-itself.stderr rename to src/test/ui/generator/generator-yielding-or-returning-itself.stderr diff --git a/src/test/ui/generator/issue-64620-yield-array-element.rs b/src/test/ui/generator/issue-64620-yield-array-element.rs new file mode 100644 index 00000000000..2cbe8f51614 --- /dev/null +++ b/src/test/ui/generator/issue-64620-yield-array-element.rs @@ -0,0 +1,9 @@ +// Regression test for #64620 + +#![feature(generators)] + +pub fn crash(arr: [usize; 1]) { + yield arr[0]; //~ ERROR: yield expression outside of generator literal +} + +fn main() {} diff --git a/src/test/ui/generator/issue-64620-yield-array-element.stderr b/src/test/ui/generator/issue-64620-yield-array-element.stderr new file mode 100644 index 00000000000..48383c2ed08 --- /dev/null +++ b/src/test/ui/generator/issue-64620-yield-array-element.stderr @@ -0,0 +1,9 @@ +error[E0627]: yield expression outside of generator literal + --> $DIR/issue-64620-yield-array-element.rs:6:5 + | +LL | yield arr[0]; + | ^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0627`. diff --git a/src/test/ui/generator/issue-69039.rs b/src/test/ui/generator/issue-69039.rs new file mode 100644 index 00000000000..ccc141860aa --- /dev/null +++ b/src/test/ui/generator/issue-69039.rs @@ -0,0 +1,34 @@ +// run-pass + +#![feature(generators, generator_trait)] + +use std::ops::{Generator, GeneratorState}; + +fn mkstr(my_name: String, my_mood: String) -> String { + format!("{} is {}", my_name.trim(), my_mood.trim()) +} + +fn my_scenario() -> impl Generator { + |_arg: String| { + let my_name = yield "What is your name?"; + let my_mood = yield "How are you feeling?"; + mkstr(my_name, my_mood) + } +} + +fn main() { + let mut my_session = Box::pin(my_scenario()); + + assert_eq!( + my_session.as_mut().resume("_arg".to_string()), + GeneratorState::Yielded("What is your name?") + ); + assert_eq!( + my_session.as_mut().resume("Your Name".to_string()), + GeneratorState::Yielded("How are you feeling?") + ); + assert_eq!( + my_session.as_mut().resume("Sensory Organs".to_string()), + GeneratorState::Complete("Your Name is Sensory Organs".to_string()) + ); +} diff --git a/src/test/ui/generator/resume-arg-size.rs b/src/test/ui/generator/resume-arg-size.rs new file mode 100644 index 00000000000..4f08ac0702b --- /dev/null +++ b/src/test/ui/generator/resume-arg-size.rs @@ -0,0 +1,28 @@ +#![feature(generators)] + +// run-pass + +use std::mem::size_of_val; + +fn main() { + // Generator taking a `Copy`able resume arg. + let gen_copy = |mut x: usize| { + loop { + drop(x); + x = yield; + } + }; + + // Generator taking a non-`Copy` resume arg. + let gen_move = |mut x: Box| { + loop { + drop(x); + x = yield; + } + }; + + // Neither of these generators have the resume arg live across the `yield`, so they should be + // 4 Bytes in size (only storing the discriminant) + assert_eq!(size_of_val(&gen_copy), 1); + assert_eq!(size_of_val(&gen_move), 1); +} diff --git a/src/test/ui/generator/size-moved-locals.rs b/src/test/ui/generator/size-moved-locals.rs index 2864fbb2f3c..74c60d98154 100644 --- a/src/test/ui/generator/size-moved-locals.rs +++ b/src/test/ui/generator/size-moved-locals.rs @@ -58,7 +58,7 @@ fn overlap_move_points() -> impl Generator { } } -fn overlap_x_and_y() -> impl Generator{ +fn overlap_x_and_y() -> impl Generator { static || { let x = Foo([0; FOO_SIZE]); yield; @@ -70,8 +70,8 @@ fn overlap_x_and_y() -> impl Generator{ } fn main() { - assert_eq!(1028, std::mem::size_of_val(&move_before_yield())); - assert_eq!(1032, std::mem::size_of_val(&move_before_yield_with_noop())); - assert_eq!(2056, std::mem::size_of_val(&overlap_move_points())); - assert_eq!(1032, std::mem::size_of_val(&overlap_x_and_y())); + assert_eq!(1025, std::mem::size_of_val(&move_before_yield())); + assert_eq!(1026, std::mem::size_of_val(&move_before_yield_with_noop())); + assert_eq!(2051, std::mem::size_of_val(&overlap_move_points())); + assert_eq!(1026, std::mem::size_of_val(&overlap_x_and_y())); } diff --git a/src/test/ui/generator/too-many-parameters.stderr b/src/test/ui/generator/too-many-parameters.stderr index a297ee43de9..22d40db3f26 100644 --- a/src/test/ui/generator/too-many-parameters.stderr +++ b/src/test/ui/generator/too-many-parameters.stderr @@ -6,3 +6,4 @@ LL | |(), ()| { error: aborting due to previous error +For more information about this error, try `rustc --explain E0628`. diff --git a/src/test/ui/generic-associated-types/empty_generics.rs b/src/test/ui/generic-associated-types/empty_generics.rs index 522e23ca43d..6eb25a92f34 100644 --- a/src/test/ui/generic-associated-types/empty_generics.rs +++ b/src/test/ui/generic-associated-types/empty_generics.rs @@ -3,7 +3,7 @@ trait Foo { type Bar<,>; - //~^ ERROR expected one of `>`, `const`, identifier, or lifetime, found `,` + //~^ ERROR expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` } fn main() {} diff --git a/src/test/ui/generic-associated-types/empty_generics.stderr b/src/test/ui/generic-associated-types/empty_generics.stderr index d3acad47831..1599d683ad6 100644 --- a/src/test/ui/generic-associated-types/empty_generics.stderr +++ b/src/test/ui/generic-associated-types/empty_generics.stderr @@ -1,8 +1,13 @@ -error: expected one of `>`, `const`, identifier, or lifetime, found `,` +error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` --> $DIR/empty_generics.rs:5:14 | +LL | trait Foo { + | - while parsing this item list starting here LL | type Bar<,>; - | ^ expected one of `>`, `const`, identifier, or lifetime + | ^ expected one of `#`, `>`, `const`, identifier, or lifetime +LL | +LL | } + | - the item list ends here error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/issue-68653.rs b/src/test/ui/generic-associated-types/issue-68653.rs new file mode 100644 index 00000000000..01f4c95639d --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-68653.rs @@ -0,0 +1,16 @@ +// A regression test for #68653, which was fixed by #68938. + +// check-pass + +#![allow(incomplete_features)] +#![feature(generic_associated_types)] + +trait Fun { + type F<'a: 'a>; +} + +impl Fun for T { + type F<'a> = Self; +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/shadowing.rs b/src/test/ui/generic-associated-types/shadowing.rs index 7277c0d87c6..5c308948bd3 100644 --- a/src/test/ui/generic-associated-types/shadowing.rs +++ b/src/test/ui/generic-associated-types/shadowing.rs @@ -2,8 +2,8 @@ #![feature(generic_associated_types)] trait Shadow<'a> { - //FIXME(#44265): The lifetime parameter shadowing should cause an error. type Bar<'a>; + //~^ ERROR lifetime name `'a` shadows a lifetime name that is already in scope } trait NoShadow<'a> { @@ -11,8 +11,8 @@ trait NoShadow<'a> { } impl<'a> NoShadow<'a> for &'a u32 { - //FIXME(#44265): The lifetime parameter shadowing should cause an error. type Bar<'a> = i32; + //~^ ERROR lifetime name `'a` shadows a lifetime name that is already in scope } trait ShadowT { diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr index 3ae1e1a40c8..2d9a0d6fceb 100644 --- a/src/test/ui/generic-associated-types/shadowing.stderr +++ b/src/test/ui/generic-associated-types/shadowing.stderr @@ -14,6 +14,22 @@ LL | impl NoShadowT for Option { LL | type Bar = i32; | ^ already used +error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope + --> $DIR/shadowing.rs:5:14 + | +LL | trait Shadow<'a> { + | -- first declared here +LL | type Bar<'a>; + | ^^ lifetime 'a already in scope + +error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope + --> $DIR/shadowing.rs:14:14 + | +LL | impl<'a> NoShadow<'a> for &'a u32 { + | -- first declared here +LL | type Bar<'a> = i32; + | ^^ lifetime 'a already in scope + error: type-generic associated types are not yet implemented --> $DIR/shadowing.rs:19:5 | @@ -30,6 +46,7 @@ LL | type Bar; // OK | = note: for more information, see issue #44265 for more information -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0403`. +Some errors have detailed explanations: E0403, E0496. +For more information about an error, try `rustc --explain E0403`. diff --git a/src/test/ui/generic/generic-arg-mismatch-recover.rs b/src/test/ui/generic/generic-arg-mismatch-recover.rs index f4e15fbebce..3e5e2e601f5 100644 --- a/src/test/ui/generic/generic-arg-mismatch-recover.rs +++ b/src/test/ui/generic/generic-arg-mismatch-recover.rs @@ -4,7 +4,6 @@ struct Bar<'a>(&'a ()); fn main() { Foo::<'static, 'static, ()>(&0); //~ ERROR wrong number of lifetime arguments - //~^ ERROR mismatched types Bar::<'static, 'static, ()>(&()); //~ ERROR wrong number of lifetime arguments //~^ ERROR wrong number of type arguments diff --git a/src/test/ui/generic/generic-arg-mismatch-recover.stderr b/src/test/ui/generic/generic-arg-mismatch-recover.stderr index 4b86212e486..99adb352685 100644 --- a/src/test/ui/generic/generic-arg-mismatch-recover.stderr +++ b/src/test/ui/generic/generic-arg-mismatch-recover.stderr @@ -4,28 +4,18 @@ error[E0107]: wrong number of lifetime arguments: expected 1, found 2 LL | Foo::<'static, 'static, ()>(&0); | ^^^^^^^ unexpected lifetime argument -error[E0308]: mismatched types - --> $DIR/generic-arg-mismatch-recover.rs:6:33 - | -LL | Foo::<'static, 'static, ()>(&0); - | ^^ expected `()`, found integer - | - = note: expected reference `&'static ()` - found reference `&{integer}` - error[E0107]: wrong number of lifetime arguments: expected 1, found 2 - --> $DIR/generic-arg-mismatch-recover.rs:9:20 + --> $DIR/generic-arg-mismatch-recover.rs:8:20 | LL | Bar::<'static, 'static, ()>(&()); | ^^^^^^^ unexpected lifetime argument error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/generic-arg-mismatch-recover.rs:9:29 + --> $DIR/generic-arg-mismatch-recover.rs:8:29 | LL | Bar::<'static, 'static, ()>(&()); | ^^ unexpected type argument -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0107, E0308. -For more information about an error, try `rustc --explain E0107`. +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/hrtb/issue-58451.rs b/src/test/ui/hrtb/issue-58451.rs index 229e5057678..f36d549e476 100644 --- a/src/test/ui/hrtb/issue-58451.rs +++ b/src/test/ui/hrtb/issue-58451.rs @@ -9,5 +9,5 @@ where {} fn main() { - f(&[f()]); //~ ERROR this function takes 1 parameter + f(&[f()]); //~ ERROR this function takes 1 argument } diff --git a/src/test/ui/hrtb/issue-58451.stderr b/src/test/ui/hrtb/issue-58451.stderr index 4648c0182b9..c0915808bf5 100644 --- a/src/test/ui/hrtb/issue-58451.stderr +++ b/src/test/ui/hrtb/issue-58451.stderr @@ -1,4 +1,4 @@ -error[E0061]: this function takes 1 parameter but 0 parameters were supplied +error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/issue-58451.rs:12:9 | LL | / fn f(i: I) @@ -9,7 +9,9 @@ LL | | {} | |__- defined here ... LL | f(&[f()]); - | ^^^ expected 1 parameter + | ^-- supplied 0 arguments + | | + | expected 1 argument error: aborting due to previous error diff --git a/src/test/ui/huge-array-simple-32.rs b/src/test/ui/huge-array-simple-32.rs index 3e574dfa07b..2290e3d5e76 100644 --- a/src/test/ui/huge-array-simple-32.rs +++ b/src/test/ui/huge-array-simple-32.rs @@ -4,7 +4,7 @@ // FIXME https://github.com/rust-lang/rust/issues/59774 // normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" -#![allow(exceeding_bitshifts)] +#![allow(arithmetic_overflow)] fn main() { let _fat: [u8; (1<<31)+(1<<15)] = //~ ERROR too big for the current architecture diff --git a/src/test/ui/huge-array-simple-64.rs b/src/test/ui/huge-array-simple-64.rs index d4c93301283..02c961fc5fa 100644 --- a/src/test/ui/huge-array-simple-64.rs +++ b/src/test/ui/huge-array-simple-64.rs @@ -4,7 +4,7 @@ // FIXME https://github.com/rust-lang/rust/issues/59774 // normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" // normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" -#![allow(exceeding_bitshifts)] +#![allow(arithmetic_overflow)] fn main() { let _fat: [u8; (1<<61)+(1<<31)] = //~ ERROR too big for the current architecture diff --git a/src/test/ui/hygiene/fields-definition.stderr b/src/test/ui/hygiene/fields-definition.stderr index 8070ffdfdeb..fd8846bb13c 100644 --- a/src/test/ui/hygiene/fields-definition.stderr +++ b/src/test/ui/hygiene/fields-definition.stderr @@ -1,10 +1,10 @@ error[E0124]: field `a` is already declared - --> $DIR/fields-definition.rs:14:17 + --> $DIR/fields-definition.rs:14:13 | LL | a: u8, | ----- `a` first declared here LL | $a: u8, - | ^^ field already declared + | ^^^^^^ field already declared ... LL | legacy!(a); | ----------- in this macro invocation diff --git a/src/test/ui/hygiene/macro-metavars-legacy.rs b/src/test/ui/hygiene/macro-metavars-legacy.rs new file mode 100644 index 00000000000..09070f0f561 --- /dev/null +++ b/src/test/ui/hygiene/macro-metavars-legacy.rs @@ -0,0 +1,29 @@ +// Ensure macro metavariables are compared with legacy hygiene + +#![feature(rustc_attrs)] + +// run-pass + +macro_rules! make_mac { + ( $($dollar:tt $arg:ident),+ ) => { + macro_rules! mac { + ( $($dollar $arg : ident),+ ) => { + $( $dollar $arg )-+ + } + } + } +} + +macro_rules! show_hygiene { + ( $dollar:tt $arg:ident ) => { + make_mac!($dollar $arg, $dollar arg); + } +} + +show_hygiene!( $arg ); + +fn main() { + let x = 5; + let y = 3; + assert_eq!(2, mac!(x, y)); +} diff --git a/src/test/ui/hygiene/macro-metavars-transparent.rs b/src/test/ui/hygiene/macro-metavars-transparent.rs new file mode 100644 index 00000000000..e475b5728a0 --- /dev/null +++ b/src/test/ui/hygiene/macro-metavars-transparent.rs @@ -0,0 +1,24 @@ +// Ensure macro metavariables are not compared without removing transparent +// marks. + +#![feature(rustc_attrs)] + +// run-pass + +#[rustc_macro_transparency = "transparent"] +macro_rules! k { + ($($s:tt)*) => { + macro_rules! m { + ($y:tt) => { + $($s)* + } + } + } +} + +k!(1 + $y); + +fn main() { + let x = 2; + assert_eq!(3, m!(x)); +} diff --git a/src/test/ui/if-attrs/bad-cfg.rs b/src/test/ui/if-attrs/bad-cfg.rs new file mode 100644 index 00000000000..3f84929a00e --- /dev/null +++ b/src/test/ui/if-attrs/bad-cfg.rs @@ -0,0 +1,5 @@ +#![feature(stmt_expr_attributes)] + +fn main() { + let _ = #[cfg(FALSE)] if true {}; //~ ERROR removing an expression +} diff --git a/src/test/ui/if-attrs/bad-cfg.stderr b/src/test/ui/if-attrs/bad-cfg.stderr new file mode 100644 index 00000000000..8a2890886a1 --- /dev/null +++ b/src/test/ui/if-attrs/bad-cfg.stderr @@ -0,0 +1,8 @@ +error: removing an expression is not supported in this position + --> $DIR/bad-cfg.rs:4:13 + | +LL | let _ = #[cfg(FALSE)] if true {}; + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/if-attrs/builtin-if-attr.rs b/src/test/ui/if-attrs/builtin-if-attr.rs new file mode 100644 index 00000000000..7e290661501 --- /dev/null +++ b/src/test/ui/if-attrs/builtin-if-attr.rs @@ -0,0 +1,12 @@ +// check-pass + +fn main() { + #[allow(unused_variables)] + if true { + let a = 1; + } else if false { + let b = 1; + } else { + let c = 1; + } +} diff --git a/src/test/ui/if-attrs/cfg-false-if-attr.rs b/src/test/ui/if-attrs/cfg-false-if-attr.rs new file mode 100644 index 00000000000..1f77a1bb342 --- /dev/null +++ b/src/test/ui/if-attrs/cfg-false-if-attr.rs @@ -0,0 +1,43 @@ +// check-pass + +#[cfg(FALSE)] +fn simple_attr() { + #[attr] if true {} + #[allow_warnings] if true {} +} + +#[cfg(FALSE)] +fn if_else_chain() { + #[first_attr] if true { + } else if false { + } else { + } +} + +#[cfg(FALSE)] +fn if_let() { + #[attr] if let Some(_) = Some(true) {} +} + +fn bar() { + #[cfg(FALSE)] + if true { + let x: () = true; // Should not error due to the #[cfg(FALSE)] + } + + #[cfg_attr(not(unset_attr), cfg(FALSE))] + if true { + let a: () = true; // Should not error due to the applied #[cfg(FALSE)] + } +} + +macro_rules! custom_macro { + ($expr:expr) => {} +} + +custom_macro! { + #[attr] if true {} +} + + +fn main() {} diff --git a/src/test/ui/if-attrs/else-attrs.rs b/src/test/ui/if-attrs/else-attrs.rs new file mode 100644 index 00000000000..85da7cf6bb8 --- /dev/null +++ b/src/test/ui/if-attrs/else-attrs.rs @@ -0,0 +1,25 @@ +#[cfg(FALSE)] +fn if_else_parse_error() { + if true { + } #[attr] else if false { //~ ERROR expected + } +} + +#[cfg(FALSE)] +fn else_attr_ifparse_error() { + if true { + } else #[attr] if false { //~ ERROR outer attributes are not allowed + } else { + } +} + +#[cfg(FALSE)] +fn else_parse_error() { + if true { + } else if false { + } #[attr] else { //~ ERROR expected + } +} + +fn main() { +} diff --git a/src/test/ui/if-attrs/else-attrs.stderr b/src/test/ui/if-attrs/else-attrs.stderr new file mode 100644 index 00000000000..2733377054d --- /dev/null +++ b/src/test/ui/if-attrs/else-attrs.stderr @@ -0,0 +1,26 @@ +error: expected expression, found keyword `else` + --> $DIR/else-attrs.rs:4:15 + | +LL | } #[attr] else if false { + | ^^^^ expected expression + +error: outer attributes are not allowed on `if` and `else` branches + --> $DIR/else-attrs.rs:11:12 + | +LL | } else #[attr] if false { + | _______----_^^^^^^^_- + | | | | + | | | help: remove the attributes + | | the branch belongs to this `else` +LL | | } else { +LL | | } + | |_____- the attributes are attached to this branch + +error: expected expression, found keyword `else` + --> $DIR/else-attrs.rs:20:15 + | +LL | } #[attr] else { + | ^^^^ expected expression + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/if-attrs/gate-whole-expr.rs b/src/test/ui/if-attrs/gate-whole-expr.rs new file mode 100644 index 00000000000..63772d54b53 --- /dev/null +++ b/src/test/ui/if-attrs/gate-whole-expr.rs @@ -0,0 +1,15 @@ +// run-pass + +fn main() { + let x = 1; + + #[cfg(FALSE)] + if false { + x = 2; + } else if true { + x = 3; + } else { + x = 4; + } + assert_eq!(x, 1); +} diff --git a/src/test/ui/if-attrs/let-chains-attr.rs b/src/test/ui/if-attrs/let-chains-attr.rs new file mode 100644 index 00000000000..5237a9ff396 --- /dev/null +++ b/src/test/ui/if-attrs/let-chains-attr.rs @@ -0,0 +1,13 @@ +// check-pass + +#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete + +#[cfg(FALSE)] +fn foo() { + #[attr] + if let Some(_) = Some(true) && let Ok(_) = Ok(1) { + } else if let Some(false) = Some(true) { + } +} + +fn main() {} diff --git a/src/test/ui/if-attrs/let-chains-attr.stderr b/src/test/ui/if-attrs/let-chains-attr.stderr new file mode 100644 index 00000000000..a6c91bb9203 --- /dev/null +++ b/src/test/ui/if-attrs/let-chains-attr.stderr @@ -0,0 +1,8 @@ +warning: the feature `let_chains` is incomplete and may cause the compiler to crash + --> $DIR/let-chains-attr.rs:3:12 + | +LL | #![feature(let_chains)] + | ^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/if-attrs/stmt-expr-gated.rs b/src/test/ui/if-attrs/stmt-expr-gated.rs new file mode 100644 index 00000000000..38599c8e67c --- /dev/null +++ b/src/test/ui/if-attrs/stmt-expr-gated.rs @@ -0,0 +1,6 @@ +fn main() { + let _ = #[deny(warnings)] if true { //~ ERROR attributes on expressions + } else if false { + } else { + }; +} diff --git a/src/test/ui/if-attrs/stmt-expr-gated.stderr b/src/test/ui/if-attrs/stmt-expr-gated.stderr new file mode 100644 index 00000000000..47dac39a9ae --- /dev/null +++ b/src/test/ui/if-attrs/stmt-expr-gated.stderr @@ -0,0 +1,12 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt-expr-gated.rs:2:13 + | +LL | let _ = #[deny(warnings)] if true { + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 0ebaac89450..3d60cbff320 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -4,9 +4,34 @@ error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0` LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ | +note: ...which requires borrow-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... @@ -15,9 +40,34 @@ note: ...which requires processing `cycle2::{{opaque}}#0`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ +note: ...which requires borrow-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... @@ -40,9 +90,34 @@ error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0` LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ | +note: ...which requires borrow-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... @@ -51,9 +126,34 @@ note: ...which requires processing `cycle2::{{opaque}}#0`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ +note: ...which requires borrow-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle @@ -75,9 +175,34 @@ error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0` LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^ | +note: ...which requires borrow-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle1`... --> $DIR/auto-trait-leak.rs:12:1 | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:12:1 + | +LL | fn cycle1() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle1`... + --> $DIR/auto-trait-leak.rs:12:1 + | LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... @@ -86,9 +211,34 @@ note: ...which requires processing `cycle2::{{opaque}}#0`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^ +note: ...which requires borrow-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires processing `cycle2`... --> $DIR/auto-trait-leak.rs:22:1 | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires processing `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires unsafety-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires building MIR for... + --> $DIR/auto-trait-leak.rs:22:1 + | +LL | fn cycle2() -> impl Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `cycle2`... + --> $DIR/auto-trait-leak.rs:22:1 + | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle diff --git a/src/test/ui/impl-trait/equal-hidden-lifetimes.rs b/src/test/ui/impl-trait/equal-hidden-lifetimes.rs new file mode 100644 index 00000000000..79db88828b9 --- /dev/null +++ b/src/test/ui/impl-trait/equal-hidden-lifetimes.rs @@ -0,0 +1,49 @@ +// Test that we consider equal regions when checking for hidden regions in +// opaque types + +// check-pass + +// `'a == 'static` so `&'a i32` is fine as the return type +fn equal_regions_static<'a: 'static>(x: &'a i32) -> impl Sized { + //~^ WARNING unnecessary lifetime parameter `'a` + x +} + +// `'a == 'b` so `&'b i32` is fine as the return type +fn equal_regions<'a: 'b, 'b: 'a>(x: &'b i32) -> impl Sized + 'a { + let y: &'a i32 = x; + let z: &'b i32 = y; + x +} + +// `'a == 'b` so `&'a i32` is fine as the return type +fn equal_regions_rev<'a: 'b, 'b: 'a>(x: &'a i32) -> impl Sized + 'b { + let y: &'a i32 = x; + let z: &'b i32 = y; + x +} + +// `'a == 'b` so `*mut &'b i32` is fine as the return type +fn equal_regions_inv<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { + let y: *mut &'a i32 = x; + let z: *mut &'b i32 = y; + x +} + +// `'a == 'b` so `*mut &'a i32` is fine as the return type +fn equal_regions_inv_rev<'a: 'b, 'b: 'a>(x: *mut &'a i32) -> impl Sized + 'b { + let y: *mut &'a i32 = x; + let z: *mut &'b i32 = y; + x +} + +// Should be able to infer `fn(&'static ())` as the return type. +fn contravariant_lub<'a, 'b: 'a, 'c: 'a, 'd: 'b + 'c>( + x: fn(&'b ()), + y: fn(&'c ()), + c: bool, +) -> impl Sized + 'a { + if c { x } else { y } +} + +fn main() {} diff --git a/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr b/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr new file mode 100644 index 00000000000..eb064b4e14a --- /dev/null +++ b/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr @@ -0,0 +1,8 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/equal-hidden-lifetimes.rs:7:25 + | +LL | fn equal_regions_static<'a: 'static>(x: &'a i32) -> impl Sized { + | ^^^^^^^^^^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + diff --git a/src/test/ui/impl-trait/issue-57200.rs b/src/test/ui/impl-trait/issue-57200.rs new file mode 100644 index 00000000000..e0c71d1ac9a --- /dev/null +++ b/src/test/ui/impl-trait/issue-57200.rs @@ -0,0 +1,15 @@ +// Regression test for #57200 +// FIXME: The error is temporary hack, we'll revisit here at some point. + +#![feature(impl_trait_in_bindings)] +#![allow(incomplete_features)] + +fn bug<'a, 'b, T>() +where + 'a: 'b, +{ + let f: impl Fn(&'a T) -> &'b T = |x| x; + //~^ ERROR: lifetimes in impl Trait types in bindings are not currently supported +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-57200.stderr b/src/test/ui/impl-trait/issue-57200.stderr new file mode 100644 index 00000000000..b44f332d58c --- /dev/null +++ b/src/test/ui/impl-trait/issue-57200.stderr @@ -0,0 +1,8 @@ +error: lifetimes in impl Trait types in bindings are not currently supported + --> $DIR/issue-57200.rs:11:12 + | +LL | let f: impl Fn(&'a T) -> &'b T = |x| x; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/issue-57201.rs b/src/test/ui/impl-trait/issue-57201.rs new file mode 100644 index 00000000000..c1a98d8897b --- /dev/null +++ b/src/test/ui/impl-trait/issue-57201.rs @@ -0,0 +1,15 @@ +// Regression test for #57201 +// FIXME: The error is temporary hack, we'll revisit here at some point. + +#![feature(impl_trait_in_bindings)] +#![allow(incomplete_features)] + +fn bug<'a, 'b, T>() +where + 'a: 'b, +{ + let f: &impl Fn(&'a T) -> &'b T = &|x| x; + //~^ ERROR: lifetimes in impl Trait types in bindings are not currently supported +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-57201.stderr b/src/test/ui/impl-trait/issue-57201.stderr new file mode 100644 index 00000000000..462b17bf45e --- /dev/null +++ b/src/test/ui/impl-trait/issue-57201.stderr @@ -0,0 +1,8 @@ +error: lifetimes in impl Trait types in bindings are not currently supported + --> $DIR/issue-57201.rs:11:13 + | +LL | let f: &impl Fn(&'a T) -> &'b T = &|x| x; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/impl-trait/issue-60473.rs b/src/test/ui/impl-trait/issue-60473.rs new file mode 100644 index 00000000000..50cf0c8c6d6 --- /dev/null +++ b/src/test/ui/impl-trait/issue-60473.rs @@ -0,0 +1,17 @@ +// Regression test for #60473 + +#![feature(impl_trait_in_bindings)] +#![allow(incomplete_features)] + +struct A<'a>(&'a ()); + +trait Trait { +} + +impl Trait for () { +} + +fn main() { + let x: impl Trait = (); // FIXME: The error doesn't seem correct. + //~^ ERROR: opaque type expands to a recursive type +} diff --git a/src/test/ui/impl-trait/issue-60473.stderr b/src/test/ui/impl-trait/issue-60473.stderr new file mode 100644 index 00000000000..2d95be4e52c --- /dev/null +++ b/src/test/ui/impl-trait/issue-60473.stderr @@ -0,0 +1,11 @@ +error[E0720]: opaque type expands to a recursive type + --> $DIR/issue-60473.rs:15:12 + | +LL | let x: impl Trait = (); // FIXME: The error doesn't seem correct. + | ^^^^^^^^^^^^^ expands to a recursive type + | + = note: type resolves to itself + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0720`. diff --git a/src/test/ui/impl-trait/issue-67166.rs b/src/test/ui/impl-trait/issue-67166.rs new file mode 100644 index 00000000000..de7433a9bfc --- /dev/null +++ b/src/test/ui/impl-trait/issue-67166.rs @@ -0,0 +1,11 @@ +// Regression test for #67166 + +#![feature(impl_trait_in_bindings)] +#![allow(incomplete_features)] + +pub fn run() { + let _foo: Box = Box::new(()); // FIXME: The error doesn't much make sense. + //~^ ERROR: opaque type expands to a recursive type +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issue-67166.stderr b/src/test/ui/impl-trait/issue-67166.stderr new file mode 100644 index 00000000000..56cba3cff0b --- /dev/null +++ b/src/test/ui/impl-trait/issue-67166.stderr @@ -0,0 +1,11 @@ +error[E0720]: opaque type expands to a recursive type + --> $DIR/issue-67166.rs:7:19 + | +LL | let _foo: Box = Box::new(()); // FIXME: The error doesn't much make sense. + | ^^^^^^^^^^^^^^ expands to a recursive type + | + = note: type resolves to itself + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0720`. diff --git a/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr index 57417975474..64cce056a26 100644 --- a/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr +++ b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr @@ -8,8 +8,11 @@ LL | f1.foo(1usize); | ^^^ method not found in `Bar` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `foo`, perhaps you need to implement it: - candidate #1: `Foo` +note: `Foo` defines an item `foo`, perhaps you need to implement it + --> $DIR/issue-21659-show-relevant-trait-impls-3.rs:1:1 + | +LL | trait Foo { + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs new file mode 100644 index 00000000000..96d891b2cf1 --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.rs @@ -0,0 +1,29 @@ +// compile-flags:-Zborrowck=mir + +#![feature(member_constraints)] +#![feature(type_alias_impl_trait)] + +#[derive(Clone)] +struct CopyIfEq(T, U); + +impl Copy for CopyIfEq {} + +type E<'a, 'b> = impl Sized; + +fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds + let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y); + + // This assignment requires that `x` and `y` have the same type due to the + // `Copy` impl. The reason why we are using a copy to create a constraint + // is that only borrow checking (not regionck in type checking) enforces + // this bound. + let u = v; + let _: *mut &'a i32 = u.1; + unsafe { + let _: &'b i32 = *u.0; + } + u.0 +} + +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr new file mode 100644 index 00000000000..59105f11805 --- /dev/null +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr @@ -0,0 +1,15 @@ +error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds + --> $DIR/error-handling-2.rs:13:60 + | +LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + | ^^^^^^^^^ + | +note: hidden type `*mut &'a i32` captures the lifetime `'a` as defined on the function body at 13:8 + --> $DIR/error-handling-2.rs:13:8 + | +LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs index b226cf058aa..8d02d635094 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs @@ -11,11 +11,18 @@ impl Copy for CopyIfEq {} type E<'a, 'b> = impl Sized; fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { - //~^ ERROR lifetime may not live long enough - let v = CopyIfEq::<*mut _, *mut _>(&mut {x}, &mut y); + let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y); + + // This assignment requires that `x` and `y` have the same type due to the + // `Copy` impl. The reason why we are using a copy to create a constraint + // is that only borrow checking (not regionck in type checking) enforces + // this bound. let u = v; let _: *mut &'a i32 = u.1; - unsafe { let _: &'b i32 = *u.0; } + unsafe { + let _: &'b i32 = *u.0; + //~^ ERROR lifetime may not live long enough + } u.0 } diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr index 5957ecbdc5f..6ce3aaf49eb 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.stderr @@ -1,14 +1,15 @@ error: lifetime may not live long enough - --> $DIR/error-handling.rs:13:56 + --> $DIR/error-handling.rs:23:16 | LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { - | -- lifetime `'a` defined here ^^^^^^^^^ opaque type requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` -help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound - | -LL | type E<'a, 'b> = impl Sized + 'a; - | + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +... +LL | let _: &'b i32 = *u.0; + | ^^^^^^^ type annotation requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr index a255c48ec6e..5bfc446f6a5 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr @@ -3,6 +3,8 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea | LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> | ^^^^^^^^^^^^^^^^^^ + | + = note: hidden type `Ordinary<'_>` captures lifetime '_#8r error: aborting due to previous error diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr index af42ed1c5c1..7291eee7b9e 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr @@ -3,6 +3,8 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea | LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> | ^^^^^^^^^^^^^^^^^^ + | + = note: hidden type `Ordinary<'_>` captures lifetime '_#5r error: aborting due to previous error diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs index 1c3b5ac7613..00f3490991b 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs @@ -12,7 +12,7 @@ impl<'a> LifetimeTrait<'a> for &'a i32 {} fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } //~^ ERROR cannot infer an appropriate lifetime -// Tests that a closure type contianing 'b cannot be returned from a type where +// Tests that a closure type containing 'b cannot be returned from a type where // only 'a was expected. fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { //~^ ERROR lifetime mismatch diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 7f92e709af5..cffa5ee8f14 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -67,7 +67,7 @@ error[E0310]: the parameter type `T` may not live long enough LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { | -- ^^^^^^^^^^^^^^^^^^^^ | | - | help: consider adding an explicit lifetime bound `T: 'static`... + | help: consider adding an explicit lifetime bound...: `T: 'static +` | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/must_outlive_least_region_or_bound.rs:22:51 diff --git a/src/test/ui/impl-trait/nested-return-type.rs b/src/test/ui/impl-trait/nested-return-type.rs new file mode 100644 index 00000000000..7d7a084b890 --- /dev/null +++ b/src/test/ui/impl-trait/nested-return-type.rs @@ -0,0 +1,16 @@ +// Check that nested impl Trait items work in functions with generic parameters. +// check-pass + +trait Captures<'a> {} + +impl Captures<'_> for T {} + +fn nested_assoc_type<'a: 'a, T>() -> impl Iterator { + [1].iter() +} + +fn nested_assoc_lifetime<'a: 'a, T>() -> impl Iterator> { + [1].iter() +} + +fn main() {} diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index da25617e187..c0ca341385d 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -126,8 +126,11 @@ LL | 1u64.method2(); | ^^^^^^^ method not found in `u64` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&u64>>` in the current scope --> $DIR/no-method-suggested-traits.rs:47:44 @@ -136,8 +139,11 @@ LL | std::rc::Rc::new(&mut Box::new(&1u64)).method2(); | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&u64>>` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method2` found for struct `no_method_suggested_traits::Foo` in the current scope --> $DIR/no-method-suggested-traits.rs:50:37 @@ -146,8 +152,11 @@ LL | no_method_suggested_traits::Foo.method2(); | ^^^^^^^ method not found in `no_method_suggested_traits::Foo` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:52:71 @@ -156,8 +165,11 @@ LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).metho | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method2` found for enum `no_method_suggested_traits::Bar` in the current scope --> $DIR/no-method-suggested-traits.rs:54:40 @@ -166,8 +178,11 @@ LL | no_method_suggested_traits::Bar::X.method2(); | ^^^^^^^ method not found in `no_method_suggested_traits::Bar` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope --> $DIR/no-method-suggested-traits.rs:56:74 @@ -176,8 +191,11 @@ LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).me | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `method2`, perhaps you need to implement it: - candidate #1: `foo::Bar` +note: `foo::Bar` defines an item `method2`, perhaps you need to implement it + --> $DIR/no-method-suggested-traits.rs:8:5 + | +LL | pub trait Bar { + | ^^^^^^^^^^^^^ error[E0599]: no method named `method3` found for struct `Foo` in the current scope --> $DIR/no-method-suggested-traits.rs:59:9 diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs index 2b4f5e0975a..3cc53744097 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.rs @@ -1,6 +1,9 @@ // Test that an `impl Trait` type that expands to itself is an error. -fn test() -> impl Sized { //~ ERROR E0720 +#![allow(unconditional_recursion)] + +fn test() -> impl Sized { + //~^ ERROR E0720 test() } diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr index 1b5dbd814a4..5a95e2969d1 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr @@ -1,5 +1,5 @@ error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-direct.rs:3:14 + --> $DIR/recursive-impl-trait-type-direct.rs:5:14 | LL | fn test() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs index 2428b560b70..e3c621f0c57 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.rs @@ -2,59 +2,75 @@ // otherwise forbidden. #![feature(generators)] +#![allow(unconditional_recursion)] -fn option(i: i32) -> impl Sized { //~ ERROR - if i < 0 { - None - } else { - Some((option(i - 1), i)) - } +fn option(i: i32) -> impl Sized { + //~^ ERROR + if i < 0 { None } else { Some((option(i - 1), i)) } } -fn tuple() -> impl Sized { //~ ERROR +fn tuple() -> impl Sized { + //~^ ERROR (tuple(),) } -fn array() -> impl Sized { //~ ERROR +fn array() -> impl Sized { + //~^ ERROR [array()] } -fn ptr() -> impl Sized { //~ ERROR +fn ptr() -> impl Sized { + //~^ ERROR &ptr() as *const _ } -fn fn_ptr() -> impl Sized { //~ ERROR +fn fn_ptr() -> impl Sized { + //~^ ERROR fn_ptr as fn() -> _ } -fn closure_capture() -> impl Sized { //~ ERROR +fn closure_capture() -> impl Sized { + //~^ ERROR let x = closure_capture(); - move || { x; } + move || { + x; + } } -fn closure_ref_capture() -> impl Sized { //~ ERROR +fn closure_ref_capture() -> impl Sized { + //~^ ERROR let x = closure_ref_capture(); - move || { &x; } + move || { + &x; + } } -fn closure_sig() -> impl Sized { //~ ERROR +fn closure_sig() -> impl Sized { + //~^ ERROR || closure_sig() } -fn generator_sig() -> impl Sized { //~ ERROR +fn generator_sig() -> impl Sized { + //~^ ERROR || generator_sig() } -fn generator_capture() -> impl Sized { //~ ERROR +fn generator_capture() -> impl Sized { + //~^ ERROR let x = generator_capture(); - move || { yield; x; } + move || { + yield; + x; + } } -fn substs_change() -> impl Sized { //~ ERROR +fn substs_change() -> impl Sized { + //~^ ERROR (substs_change::<&T>(),) } -fn generator_hold() -> impl Sized { //~ ERROR +fn generator_hold() -> impl Sized { + //~^ ERROR move || { let x = generator_hold(); yield; @@ -62,15 +78,18 @@ fn generator_hold() -> impl Sized { //~ ERROR } } -fn use_fn_ptr() -> impl Sized { // OK, error already reported +fn use_fn_ptr() -> impl Sized { + // OK, error already reported fn_ptr() } -fn mutual_recursion() -> impl Sync { //~ ERROR +fn mutual_recursion() -> impl Sync { + //~^ ERROR mutual_recursion_b() } -fn mutual_recursion_b() -> impl Sized { //~ ERROR +fn mutual_recursion_b() -> impl Sized { + //~^ ERROR mutual_recursion() } diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index b7ba0d6ab17..6573b00870c 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -1,5 +1,5 @@ error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:6:22 + --> $DIR/recursive-impl-trait-type-indirect.rs:7:22 | LL | fn option(i: i32) -> impl Sized { | ^^^^^^^^^^ expands to a recursive type @@ -7,7 +7,7 @@ LL | fn option(i: i32) -> impl Sized { = note: expanded type is `std::option::Option<(impl Sized, i32)>` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:14:15 + --> $DIR/recursive-impl-trait-type-indirect.rs:12:15 | LL | fn tuple() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type @@ -15,7 +15,7 @@ LL | fn tuple() -> impl Sized { = note: expanded type is `(impl Sized,)` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:18:15 + --> $DIR/recursive-impl-trait-type-indirect.rs:17:15 | LL | fn array() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type @@ -31,7 +31,7 @@ LL | fn ptr() -> impl Sized { = note: expanded type is `*const impl Sized` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:26:16 + --> $DIR/recursive-impl-trait-type-indirect.rs:27:16 | LL | fn fn_ptr() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type @@ -39,63 +39,63 @@ LL | fn fn_ptr() -> impl Sized { = note: expanded type is `fn() -> impl Sized` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:30:25 + --> $DIR/recursive-impl-trait-type-indirect.rs:32:25 | LL | fn closure_capture() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:32:5: 32:19 x:impl Sized]` + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:35:29 + --> $DIR/recursive-impl-trait-type-indirect.rs:40:29 | LL | fn closure_ref_capture() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:37:5: 37:20 x:impl Sized]` + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:40:21 + --> $DIR/recursive-impl-trait-type-indirect.rs:48:21 | LL | fn closure_sig() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:41:5: 41:21]` + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:21]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:44:23 + --> $DIR/recursive-impl-trait-type-indirect.rs:53:23 | LL | fn generator_sig() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:45:5: 45:23]` + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:23]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:48:27 + --> $DIR/recursive-impl-trait-type-indirect.rs:58:27 | LL | fn generator_capture() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:26 x:impl Sized {()}]` + = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:53:26 + --> $DIR/recursive-impl-trait-type-indirect.rs:67:35 | -LL | fn substs_change() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type +LL | fn substs_change() -> impl Sized { + | ^^^^^^^^^^ expands to a recursive type | = note: expanded type is `(impl Sized,)` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:57:24 + --> $DIR/recursive-impl-trait-type-indirect.rs:72:24 | LL | fn generator_hold() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type | - = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:58:5: 62:6 {impl Sized, ()}]` + = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]` error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:69:26 + --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 | LL | fn mutual_recursion() -> impl Sync { | ^^^^^^^^^ expands to a recursive type @@ -103,7 +103,7 @@ LL | fn mutual_recursion() -> impl Sync { = note: type resolves to itself error[E0720]: opaque type expands to a recursive type - --> $DIR/recursive-impl-trait-type-indirect.rs:73:28 + --> $DIR/recursive-impl-trait-type-indirect.rs:91:28 | LL | fn mutual_recursion_b() -> impl Sized { | ^^^^^^^^^^ expands to a recursive type diff --git a/src/test/ui/impl-trait/type_parameters_captured.stderr b/src/test/ui/impl-trait/type_parameters_captured.stderr index 708b479ab17..34f0f7f1d73 100644 --- a/src/test/ui/impl-trait/type_parameters_captured.stderr +++ b/src/test/ui/impl-trait/type_parameters_captured.stderr @@ -4,7 +4,7 @@ error[E0310]: the parameter type `T` may not live long enough LL | fn foo(x: T) -> impl Any + 'static { | - ^^^^^^^^^^^^^^^^^^ | | - | help: consider adding an explicit lifetime bound `T: 'static`... + | help: consider adding an explicit lifetime bound...: `T: 'static` | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/type_parameters_captured.rs:7:20 diff --git a/src/test/ui/impl-trait/unsafety-checking-cycle.rs b/src/test/ui/impl-trait/unsafety-checking-cycle.rs new file mode 100644 index 00000000000..4a5831c5b73 --- /dev/null +++ b/src/test/ui/impl-trait/unsafety-checking-cycle.rs @@ -0,0 +1,32 @@ +// Ensure that we don't get a cycle error from trying to determine whether an +// opaque type implements `Freeze` in safety checking, when it doesn't matter. + +// check-pass + +#![feature(rustc_attrs)] + +struct AnyValue(T); + +// No need to check for `Freeze` here, there's no +// `rustc_layout_scalar_valid_range_start` involved. +fn not_restricted(c: bool) -> impl Sized { + if c { + let x = AnyValue(not_restricted(false)); + &x.0; + } + 2u32 +} + +#[rustc_layout_scalar_valid_range_start(1)] +struct NonZero(T); + +// No need to check for `Freeze` here, we're not borrowing the field. +fn not_field(c: bool) -> impl Sized { + if c { + let x = unsafe { NonZero(not_field(false)) }; + &x; + } + 5u32 +} + +fn main() {} diff --git a/src/test/ui/imports/issue-55884-2.stderr b/src/test/ui/imports/issue-55884-2.stderr index f16d2adb365..490c08446b5 100644 --- a/src/test/ui/imports/issue-55884-2.stderr +++ b/src/test/ui/imports/issue-55884-2.stderr @@ -4,11 +4,26 @@ error[E0603]: struct import `ParseOptions` is private LL | pub use parser::ParseOptions; | ^^^^^^^^^^^^ this struct import is private | -note: the struct import `ParseOptions` is defined here +note: the struct import `ParseOptions` is defined here... --> $DIR/issue-55884-2.rs:9:9 | LL | use ParseOptions; | ^^^^^^^^^^^^ +note: ...and refers to the struct import `ParseOptions` which is defined here... + --> $DIR/issue-55884-2.rs:12:9 + | +LL | pub use parser::ParseOptions; + | ^^^^^^^^^^^^^^^^^^^^ consider importing it directly +note: ...and refers to the struct import `ParseOptions` which is defined here... + --> $DIR/issue-55884-2.rs:6:13 + | +LL | pub use options::*; + | ^^^^^^^^^^ consider importing it directly +note: ...and refers to the struct `ParseOptions` which is defined here + --> $DIR/issue-55884-2.rs:2:5 + | +LL | pub struct ParseOptions {} + | ^^^^^^^^^^^^^^^^^^^^^^^ consider importing it directly error: aborting due to previous error diff --git a/src/test/ui/imports/reexports.stderr b/src/test/ui/imports/reexports.stderr index 7b0d63574ec..d63fbc7ec67 100644 --- a/src/test/ui/imports/reexports.stderr +++ b/src/test/ui/imports/reexports.stderr @@ -16,11 +16,16 @@ error[E0603]: module import `foo` is private LL | use b::a::foo::S; | ^^^ this module import is private | -note: the module import `foo` is defined here +note: the module import `foo` is defined here... --> $DIR/reexports.rs:21:17 | LL | pub use super::foo; // This is OK since the value `foo` is visible enough. | ^^^^^^^^^^ +note: ...and refers to the module `foo` which is defined here + --> $DIR/reexports.rs:16:5 + | +LL | mod foo { + | ^^^^^^^ error[E0603]: module import `foo` is private --> $DIR/reexports.rs:34:15 @@ -28,11 +33,16 @@ error[E0603]: module import `foo` is private LL | use b::b::foo::S as T; | ^^^ this module import is private | -note: the module import `foo` is defined here +note: the module import `foo` is defined here... --> $DIR/reexports.rs:26:17 | LL | pub use super::*; // This is also OK since the value `foo` is visible enough. | ^^^^^^^^ +note: ...and refers to the module `foo` which is defined here + --> $DIR/reexports.rs:16:5 + | +LL | mod foo { + | ^^^^^^^ warning: glob import doesn't reexport anything because no candidate is public enough --> $DIR/reexports.rs:9:17 diff --git a/src/test/ui/inference/infer-binary-operand-behind-reference.rs b/src/test/ui/inference/infer-binary-operand-behind-reference.rs new file mode 100644 index 00000000000..0c0a3171ee9 --- /dev/null +++ b/src/test/ui/inference/infer-binary-operand-behind-reference.rs @@ -0,0 +1,30 @@ +// check-pass + +fn main() { + // Test that we can infer the type of binary operands when + // references are involved, on various types and operators. + let _: u8 = 0 + 0; + let _: u8 = 0 + &0; + let _: u8 = &0 + 0; + let _: u8 = &0 + &0; + + let _: f32 = 0.0 + 0.0; + let _: f32 = 0.0 + &0.0; + let _: f32 = &0.0 + 0.0; + let _: f32 = &0.0 + &0.0; + + let _: u8 = 0 << 0; + let _: u8 = 0 << &0; + let _: u8 = &0 << 0; + let _: u8 = &0 << &0; + + // Test type inference when variable types are indirectly inferred. + let a = 22; + let _: usize = a + &44; + + // When we have no expected type, the types of the operands is the default type. + let _ = 0 + 0; + let _ = 0 + &0; + let _ = &0 + 0; + let _ = &0 + &0; +} diff --git a/src/test/ui/init-large-type.rs b/src/test/ui/init-large-type.rs index a304fc9356b..ce905572f2a 100644 --- a/src/test/ui/init-large-type.rs +++ b/src/test/ui/init-large-type.rs @@ -1,3 +1,4 @@ +// compile-flags: -O // run-pass #![allow(unused_must_use)] @@ -10,17 +11,13 @@ #![feature(intrinsics)] -use std::thread; - -extern "rust-intrinsic" { - pub fn init() -> T; -} +use std::{mem, thread}; const SIZE: usize = 1024 * 1024; fn main() { // do the test in a new thread to avoid (spurious?) stack overflows thread::spawn(|| { - let _memory: [u8; SIZE] = unsafe { init() }; + let _memory: [u8; SIZE] = unsafe { mem::zeroed() }; }).join(); } diff --git a/src/test/ui/init-unsafe.rs b/src/test/ui/init-unsafe.rs deleted file mode 100644 index 3d65cfc2340..00000000000 --- a/src/test/ui/init-unsafe.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![allow(deprecated)] -#![feature(core_intrinsics)] - -use std::intrinsics::{init}; - -// Test that the `init` intrinsic is really unsafe -pub fn main() { - let stuff = init::(); //~ ERROR call to unsafe function is unsafe -} diff --git a/src/test/ui/init-unsafe.stderr b/src/test/ui/init-unsafe.stderr deleted file mode 100644 index e1126316af3..00000000000 --- a/src/test/ui/init-unsafe.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/init-unsafe.rs:8:17 - | -LL | let stuff = init::(); - | ^^^^^^^^^^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/intrinsics/intrinsic-move-val.rs b/src/test/ui/intrinsics/intrinsic-move-val.rs index 75b4ec365fe..b672f1ed26e 100644 --- a/src/test/ui/intrinsics/intrinsic-move-val.rs +++ b/src/test/ui/intrinsics/intrinsic-move-val.rs @@ -5,7 +5,6 @@ mod rusti { extern "rust-intrinsic" { - pub fn init() -> T; pub fn move_val_init(dst: *mut T, src: T); } } @@ -15,17 +14,17 @@ pub fn main() { // sanity check check_drops_state(0, None); - let mut x: Box = box D(1); - assert_eq!(x.0, 1); + let mut x: Option> = Some(box D(1)); + assert_eq!(x.as_ref().unwrap().0, 1); // A normal overwrite, to demonstrate `check_drops_state`. - x = box D(2); + x = Some(box D(2)); // At this point, one destructor has run, because the // overwrite of `x` drops its initial value. check_drops_state(1, Some(1)); - let mut y: Box = rusti::init(); + let mut y: Option> = std::mem::zeroed(); // An initial binding does not overwrite anything. check_drops_state(1, Some(1)); @@ -51,9 +50,9 @@ pub fn main() { // during such a destructor call. We do so after the end of // this scope. - assert_eq!(y.0, 2); - y.0 = 3; - assert_eq!(y.0, 3); + assert_eq!(y.as_ref().unwrap().0, 2); + y.as_mut().unwrap().0 = 3; + assert_eq!(y.as_ref().unwrap().0, 3); check_drops_state(1, Some(1)); } diff --git a/src/test/ui/intrinsics/intrinsic-uninit.rs b/src/test/ui/intrinsics/intrinsic-uninit.rs deleted file mode 100644 index 9555efb639b..00000000000 --- a/src/test/ui/intrinsics/intrinsic-uninit.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass -// pretty-expanded FIXME #23616 - -#![feature(intrinsics)] - -mod rusti { - extern "rust-intrinsic" { - pub fn uninit() -> T; - } -} -pub fn main() { - let _a : isize = unsafe {rusti::uninit()}; -} diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs new file mode 100644 index 00000000000..02f8ecaa4ee --- /dev/null +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -0,0 +1,170 @@ +// run-pass +// ignore-wasm32-bare compiled with panic=abort by default + +// This test checks panic emitted from `mem::{uninitialized,zeroed}`. + +#![feature(never_type)] +#![allow(deprecated, invalid_value)] + +use std::{ + mem::{self, MaybeUninit, ManuallyDrop}, + panic, + ptr::NonNull, + num, +}; + +#[allow(dead_code)] +struct Foo { + x: u8, + y: !, +} + +enum Bar {} + +#[allow(dead_code)] +enum OneVariant { Variant(i32) } + +// An enum with ScalarPair layout +#[allow(dead_code)] +enum LR { + Left(i64), + Right(i64), +} +#[allow(dead_code, non_camel_case_types)] +enum LR_NonZero { + Left(num::NonZeroI64), + Right(num::NonZeroI64), +} + +fn test_panic_msg(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) { + let err = panic::catch_unwind(op).err(); + assert_eq!( + err.as_ref().and_then(|a| a.downcast_ref::()).map(|s| &**s), + Some(msg) + ); +} + +fn main() { + unsafe { + // Uninhabited types + test_panic_msg( + || mem::uninitialized::(), + "attempted to instantiate uninhabited type `!`" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to instantiate uninhabited type `!`" + ); + test_panic_msg( + || MaybeUninit::::uninit().assume_init(), + "attempted to instantiate uninhabited type `!`" + ); + + test_panic_msg( + || mem::uninitialized::(), + "attempted to instantiate uninhabited type `Foo`" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to instantiate uninhabited type `Foo`" + ); + test_panic_msg( + || MaybeUninit::::uninit().assume_init(), + "attempted to instantiate uninhabited type `Foo`" + ); + + test_panic_msg( + || mem::uninitialized::(), + "attempted to instantiate uninhabited type `Bar`" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to instantiate uninhabited type `Bar`" + ); + test_panic_msg( + || MaybeUninit::::uninit().assume_init(), + "attempted to instantiate uninhabited type `Bar`" + ); + + // Types that do not like zero-initialziation + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `fn()` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `fn()`, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<*const dyn Send>(), + "attempted to leave type `*const dyn std::marker::Send` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::<*const dyn Send>(), + "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid" + ); + + /* FIXME(#66151) we conservatively do not error here yet. + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `LR_NonZero` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `LR_NonZero`, which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::>(), + "attempted to leave type `std::mem::ManuallyDrop` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::>(), + "attempted to zero-initialize type `std::mem::ManuallyDrop`, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::<(NonNull, u32, u32)>(), + "attempted to leave type `(std::ptr::NonNull, u32, u32)` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::<(NonNull, u32, u32)>(), + "attempted to zero-initialize type `(std::ptr::NonNull, u32, u32)`, \ + which is invalid" + ); + */ + + // Types that can be zero, but not uninit. + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `bool` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `LR` uninitialized, which is invalid" + ); + test_panic_msg( + || mem::uninitialized::>(), + "attempted to leave type `std::mem::ManuallyDrop` uninitialized, which is invalid" + ); + + // Some things that should work. + let _val = mem::zeroed::(); + let _val = mem::zeroed::(); + let _val = mem::zeroed::>(); + let _val = mem::zeroed::(); + let _val = mem::zeroed::>(); + let _val = mem::zeroed::>>(); + let _val = mem::uninitialized::>(); + + // These are UB because they have not been officially blessed, but we await the resolution + // of before doing + // anything about that. + let _val = mem::uninitialized::(); + let _val = mem::uninitialized::<*const ()>(); + } +} diff --git a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr index c95df5b4534..52296042eb4 100644 --- a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr +++ b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr @@ -1,10 +1,10 @@ error[E0583]: file not found for module `baz` - --> $DIR/auxiliary/foo/bar.rs:1:9 + --> $DIR/auxiliary/foo/bar.rs:1:1 | LL | pub mod baz; - | ^^^ + | ^^^^^^^^^^^^ | - = help: name the file either bar/baz.rs or bar/baz/mod.rs inside the directory "$DIR/auxiliary/foo" + = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs" error: aborting due to previous error diff --git a/src/test/ui/issues/auxiliary/issue-51798.rs b/src/test/ui/issues/auxiliary/issue-51798.rs new file mode 100644 index 00000000000..fef5213db9f --- /dev/null +++ b/src/test/ui/issues/auxiliary/issue-51798.rs @@ -0,0 +1,3 @@ +#![crate_type = "lib"] + +pub fn vec() -> Vec { vec![] } diff --git a/src/test/ui/issues/auxiliary/issue-69725.rs b/src/test/ui/issues/auxiliary/issue-69725.rs new file mode 100644 index 00000000000..13606e498ef --- /dev/null +++ b/src/test/ui/issues/auxiliary/issue-69725.rs @@ -0,0 +1,8 @@ +#[derive(Clone)] +pub struct Struct(A); + +impl Struct { + pub fn new() -> Self { + todo!() + } +} diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr index 60c4cceac51..45fede44106 100644 --- a/src/test/ui/issues/issue-12552.stderr +++ b/src/test/ui/issues/issue-12552.stderr @@ -12,6 +12,9 @@ LL | Some(k) => match k { error[E0308]: mismatched types --> $DIR/issue-12552.rs:9:5 | +LL | match t { + | - this expression has type `std::result::Result<_, {integer}>` +... LL | None => () | ^^^^ expected enum `std::result::Result`, found enum `std::option::Option` | diff --git a/src/test/ui/issues/issue-14915.stderr b/src/test/ui/issues/issue-14915.stderr index 00b9909af59..3c34a8a3467 100644 --- a/src/test/ui/issues/issue-14915.stderr +++ b/src/test/ui/issues/issue-14915.stderr @@ -5,8 +5,6 @@ LL | println!("{}", x + 1); | - ^ - {integer} | | | std::boxed::Box - | - = note: an implementation of `std::ops::Add` might be missing for `std::boxed::Box` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16683.nll.stderr b/src/test/ui/issues/issue-16683.nll.stderr index ea6b69d1a76..b82b0b552e2 100644 --- a/src/test/ui/issues/issue-16683.nll.stderr +++ b/src/test/ui/issues/issue-16683.nll.stderr @@ -1,10 +1,10 @@ -error[E0521]: borrowed data escapes outside of function +error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-16683.rs:4:9 | LL | fn b(&self) { - | ----- `self` is a reference that is only valid in the function body + | ----- `self` is a reference that is only valid in the associated function body LL | self.a(); - | ^^^^^^^^ `self` escapes the function body here + | ^^^^^^^^ `self` escapes the associated function body here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16939.stderr b/src/test/ui/issues/issue-16939.stderr index 5df2119c141..103f56fa04d 100644 --- a/src/test/ui/issues/issue-16939.stderr +++ b/src/test/ui/issues/issue-16939.stderr @@ -1,8 +1,10 @@ -error[E0057]: this function takes 0 parameters but 1 parameter was supplied +error[E0057]: this function takes 0 arguments but 1 argument was supplied --> $DIR/issue-16939.rs:5:9 | LL | |t| f(t); - | ^^^^ expected 0 parameters + | ^ - supplied 1 argument + | | + | expected 0 arguments error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17758.nll.stderr b/src/test/ui/issues/issue-17758.nll.stderr index b9dc9da3683..23557b4d956 100644 --- a/src/test/ui/issues/issue-17758.nll.stderr +++ b/src/test/ui/issues/issue-17758.nll.stderr @@ -1,10 +1,10 @@ -error[E0521]: borrowed data escapes outside of function +error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-17758.rs:7:9 | LL | fn bar(&self) { - | ----- `self` is a reference that is only valid in the function body + | ----- `self` is a reference that is only valid in the associated function body LL | self.foo(); - | ^^^^^^^^^^ `self` escapes the function body here + | ^^^^^^^^^^ `self` escapes the associated function body here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18819.stderr b/src/test/ui/issues/issue-18819.stderr index 41e8470ecd0..a952c9b46c9 100644 --- a/src/test/ui/issues/issue-18819.stderr +++ b/src/test/ui/issues/issue-18819.stderr @@ -1,11 +1,13 @@ -error[E0061]: this function takes 2 parameters but 1 parameter was supplied +error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-18819.rs:16:5 | LL | fn print_x(_: &dyn Foo, extra: &str) { | ----------------------------------------------- defined here ... LL | print_x(X); - | ^^^^^^^^^^ expected 2 parameters + | ^^^^^^^ - supplied 1 argument + | | + | expected 2 arguments error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-8.rs b/src/test/ui/issues/issue-20616-8.rs index c9e8b61e50b..3ceb58d1252 100644 --- a/src/test/ui/issues/issue-20616-8.rs +++ b/src/test/ui/issues/issue-20616-8.rs @@ -29,7 +29,7 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_8<'a,,> = &'a (); -//~^ error: expected one of `>`, `const`, identifier, or lifetime, found `,` +//~^ error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` //type Type_9 = Box; // error: expected identifier, found `,` diff --git a/src/test/ui/issues/issue-20616-8.stderr b/src/test/ui/issues/issue-20616-8.stderr index 479469634c5..e9f37e50fff 100644 --- a/src/test/ui/issues/issue-20616-8.stderr +++ b/src/test/ui/issues/issue-20616-8.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, `const`, identifier, or lifetime, found `,` +error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` --> $DIR/issue-20616-8.rs:31:16 | LL | type Type_8<'a,,> = &'a (); - | ^ expected one of `>`, `const`, identifier, or lifetime + | ^ expected one of `#`, `>`, `const`, identifier, or lifetime error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-9.rs b/src/test/ui/issues/issue-20616-9.rs index 1c509f26fd6..7f84284481e 100644 --- a/src/test/ui/issues/issue-20616-9.rs +++ b/src/test/ui/issues/issue-20616-9.rs @@ -32,4 +32,4 @@ type Type_5_<'a> = Type_1_<'a, ()>; type Type_9 = Box; -//~^ error: expected one of `>`, `const`, identifier, or lifetime, found `,` +//~^ error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` diff --git a/src/test/ui/issues/issue-20616-9.stderr b/src/test/ui/issues/issue-20616-9.stderr index b7e3322b7aa..dc309d1bce1 100644 --- a/src/test/ui/issues/issue-20616-9.stderr +++ b/src/test/ui/issues/issue-20616-9.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, `const`, identifier, or lifetime, found `,` +error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` --> $DIR/issue-20616-9.rs:34:15 | LL | type Type_9 = Box; - | ^ expected one of `>`, `const`, identifier, or lifetime + | ^ expected one of `#`, `>`, `const`, identifier, or lifetime error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21174.stderr b/src/test/ui/issues/issue-21174.stderr index 5ac5a8665bc..09402c3d814 100644 --- a/src/test/ui/issues/issue-21174.stderr +++ b/src/test/ui/issues/issue-21174.stderr @@ -4,8 +4,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | let new: T::B = unsafe { std::mem::transmute(value) }; | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `>::A` (size can vary because of ::A) - = note: target type: `>::B` (size can vary because of ::B) + = note: source type: `::A` (this type does not have a fixed size) + = note: target type: `::B` (this type does not have a fixed size) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21202.rs b/src/test/ui/issues/issue-21202.rs index 2c5f1394449..f62de7ce7db 100644 --- a/src/test/ui/issues/issue-21202.rs +++ b/src/test/ui/issues/issue-21202.rs @@ -8,7 +8,7 @@ mod B { use crate1::A::Foo; fn bar(f: Foo) { Foo::foo(&f); - //~^ ERROR: method `foo` is private + //~^ ERROR: associated function `foo` is private } } diff --git a/src/test/ui/issues/issue-21202.stderr b/src/test/ui/issues/issue-21202.stderr index d19e42d8d9c..18669add205 100644 --- a/src/test/ui/issues/issue-21202.stderr +++ b/src/test/ui/issues/issue-21202.stderr @@ -1,4 +1,4 @@ -error[E0624]: method `foo` is private +error[E0624]: associated function `foo` is private --> $DIR/issue-21202.rs:10:9 | LL | Foo::foo(&f); diff --git a/src/test/ui/issues/issue-21596.stderr b/src/test/ui/issues/issue-21596.stderr index efde16167b7..3e0a532b2b8 100644 --- a/src/test/ui/issues/issue-21596.stderr +++ b/src/test/ui/issues/issue-21596.stderr @@ -7,7 +7,8 @@ LL | println!("{}", z.to_string()); = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior = note: the method `to_string` exists but the following trait bounds were not satisfied: - `*const u8 : std::string::ToString` + `*const u8: std::fmt::Display` + which is required by `*const u8: std::string::ToString` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22777.rs b/src/test/ui/issues/issue-22777.rs index a31f059408f..486683d12d6 100644 --- a/src/test/ui/issues/issue-22777.rs +++ b/src/test/ui/issues/issue-22777.rs @@ -1,5 +1,5 @@ // check-pass -// This test is reduced from libsyntax. It is just checking that we +// This test is reduced from librustc_ast. It is just checking that we // can successfully deal with a "deep" structure, which the drop-check // was hitting a recursion limit on at one point. diff --git a/src/test/ui/issues/issue-23080-2.rs b/src/test/ui/issues/issue-23080-2.rs index 319aa2a5cce..d20bb4bd907 100644 --- a/src/test/ui/issues/issue-23080-2.rs +++ b/src/test/ui/issues/issue-23080-2.rs @@ -3,8 +3,7 @@ #![feature(optin_builtin_traits)] unsafe auto trait Trait { -//~^ ERROR E0380 - type Output; + type Output; //~ ERROR E0380 } fn call_method(x: T) {} diff --git a/src/test/ui/issues/issue-23080-2.stderr b/src/test/ui/issues/issue-23080-2.stderr index 1103de0d910..fcd1ecfa982 100644 --- a/src/test/ui/issues/issue-23080-2.stderr +++ b/src/test/ui/issues/issue-23080-2.stderr @@ -1,11 +1,10 @@ error[E0380]: auto traits cannot have methods or associated items - --> $DIR/issue-23080-2.rs:5:1 + --> $DIR/issue-23080-2.rs:6:10 | -LL | / unsafe auto trait Trait { -LL | | -LL | | type Output; -LL | | } - | |_^ +LL | unsafe auto trait Trait { + | ----- auto trait cannot have items +LL | type Output; + | ^^^^^^ error[E0275]: overflow evaluating the requirement `<() as Trait>::Output` | diff --git a/src/test/ui/issues/issue-23080.rs b/src/test/ui/issues/issue-23080.rs index fdfee698144..fa5c35316bc 100644 --- a/src/test/ui/issues/issue-23080.rs +++ b/src/test/ui/issues/issue-23080.rs @@ -1,8 +1,7 @@ #![feature(optin_builtin_traits)] unsafe auto trait Trait { -//~^ ERROR E0380 - fn method(&self) { + fn method(&self) { //~ ERROR E0380 println!("Hello"); } } diff --git a/src/test/ui/issues/issue-23080.stderr b/src/test/ui/issues/issue-23080.stderr index 91c27217324..dbb9861b578 100644 --- a/src/test/ui/issues/issue-23080.stderr +++ b/src/test/ui/issues/issue-23080.stderr @@ -1,13 +1,10 @@ error[E0380]: auto traits cannot have methods or associated items - --> $DIR/issue-23080.rs:3:1 + --> $DIR/issue-23080.rs:4:8 | -LL | / unsafe auto trait Trait { -LL | | -LL | | fn method(&self) { -LL | | println!("Hello"); -LL | | } -LL | | } - | |_^ +LL | unsafe auto trait Trait { + | ----- auto trait cannot have items +LL | fn method(&self) { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24363.stderr b/src/test/ui/issues/issue-24363.stderr index a60fb24ec12..16537e21ae0 100644 --- a/src/test/ui/issues/issue-24363.stderr +++ b/src/test/ui/issues/issue-24363.stderr @@ -11,8 +11,6 @@ LL | ()+() | --^-- () | | | () - | - = note: an implementation of `std::ops::Add` might be missing for `()` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-26094.rs b/src/test/ui/issues/issue-26094.rs index b9433849853..78fb0491d82 100644 --- a/src/test/ui/issues/issue-26094.rs +++ b/src/test/ui/issues/issue-26094.rs @@ -1,13 +1,13 @@ macro_rules! some_macro { ($other: expr) => ({ - $other(None) - //~^ this function takes 0 parameters but 1 parameter was supplied + $other(None) //~ NOTE supplied 1 argument }) } -fn some_function() {} +fn some_function() {} //~ NOTE defined here fn main() { some_macro!(some_function); - //~^ in this expansion of some_macro! + //~^ ERROR this function takes 0 arguments but 1 argument was supplied + //~| NOTE expected 0 arguments } diff --git a/src/test/ui/issues/issue-26094.stderr b/src/test/ui/issues/issue-26094.stderr index 0b5b6d5a750..2038d88bf46 100644 --- a/src/test/ui/issues/issue-26094.stderr +++ b/src/test/ui/issues/issue-26094.stderr @@ -1,16 +1,14 @@ -error[E0061]: this function takes 0 parameters but 1 parameter was supplied - --> $DIR/issue-26094.rs:3:9 +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/issue-26094.rs:10:17 | LL | $other(None) - | ^^^^^^^^^^^^ expected 0 parameters + | ---- supplied 1 argument ... LL | fn some_function() {} | ------------------ defined here ... LL | some_macro!(some_function); - | --------------------------- in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^^^^^^^^^^^ expected 0 arguments error: aborting due to previous error diff --git a/src/test/ui/issues/issue-28344.stderr b/src/test/ui/issues/issue-28344.stderr index 77bc8292094..e34ac45e69d 100644 --- a/src/test/ui/issues/issue-28344.stderr +++ b/src/test/ui/issues/issue-28344.stderr @@ -11,7 +11,7 @@ LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); | ^^^^^ | | | function or associated item not found in `dyn std::ops::BitXor<_>` - | help: there is a method with a similar name: `bitxor` + | help: there is an associated function with a similar name: `bitxor` error[E0191]: the value of the associated type `Output` (from trait `std::ops::BitXor`) must be specified --> $DIR/issue-28344.rs:8:13 @@ -26,7 +26,7 @@ LL | let g = BitXor::bitor; | ^^^^^ | | | function or associated item not found in `dyn std::ops::BitXor<_>` - | help: there is a method with a similar name: `bitxor` + | help: there is an associated function with a similar name: `bitxor` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-3044.rs b/src/test/ui/issues/issue-3044.rs index 26db04b69b4..81d76a90eb0 100644 --- a/src/test/ui/issues/issue-3044.rs +++ b/src/test/ui/issues/issue-3044.rs @@ -2,5 +2,5 @@ fn main() { let needlesArr: Vec = vec!['a', 'f']; needlesArr.iter().fold(|x, y| { }); - //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied + //~^^ ERROR this function takes 2 arguments but 1 argument was supplied } diff --git a/src/test/ui/issues/issue-3044.stderr b/src/test/ui/issues/issue-3044.stderr index 35a85b604b2..d2c010659ed 100644 --- a/src/test/ui/issues/issue-3044.stderr +++ b/src/test/ui/issues/issue-3044.stderr @@ -1,8 +1,12 @@ -error[E0061]: this function takes 2 parameters but 1 parameter was supplied +error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-3044.rs:3:23 | -LL | needlesArr.iter().fold(|x, y| { - | ^^^^ expected 2 parameters +LL | needlesArr.iter().fold(|x, y| { + | _______________________^^^^_- + | | | + | | expected 2 arguments +LL | | }); + | |_____- supplied 1 argument error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31076.stderr b/src/test/ui/issues/issue-31076.stderr index 5d65734cd23..4c0e1cf7ebb 100644 --- a/src/test/ui/issues/issue-31076.stderr +++ b/src/test/ui/issues/issue-31076.stderr @@ -5,8 +5,6 @@ LL | let x = 5 + 6; | - ^ - {integer} | | | {integer} - | - = note: an implementation of `std::ops::Add` might be missing for `{integer}` error[E0369]: cannot add `i32` to `i32` --> $DIR/issue-31076.rs:15:18 @@ -15,8 +13,6 @@ LL | let y = 5i32 + 6i32; | ---- ^ ---- i32 | | | i32 - | - = note: an implementation of `std::ops::Add` might be missing for `i32` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-31173.rs b/src/test/ui/issues/issue-31173.rs index 26195318380..25be266c528 100644 --- a/src/test/ui/issues/issue-31173.rs +++ b/src/test/ui/issues/issue-31173.rs @@ -1,3 +1,7 @@ +// FIXME: missing sysroot spans (#53081) +// ignore-i586-unknown-linux-gnu +// ignore-i586-unknown-linux-musl +// ignore-i686-unknown-linux-musl use std::vec::IntoIter; pub fn get_tok(it: &mut IntoIter) { diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index a614b96ac14..20bfdeea4b1 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -1,5 +1,5 @@ -error[E0271]: type mismatch resolving `, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]> as std::iter::Iterator>::Item == &_` - --> $DIR/issue-31173.rs:10:10 +error[E0271]: type mismatch resolving `, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]> as std::iter::Iterator>::Item == &_` + --> $DIR/issue-31173.rs:14:10 | LL | .cloned() | ^^^^^^ expected `u8`, found reference @@ -7,15 +7,25 @@ LL | .cloned() = note: expected type `u8` found reference `&_` -error[E0599]: no method named `collect` found for struct `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` in the current scope - --> $DIR/issue-31173.rs:14:10 +error[E0599]: no method named `collect` found for struct `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>` in the current scope + --> $DIR/issue-31173.rs:18:10 | LL | .collect(); - | ^^^^^^^ method not found in `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` + | ^^^^^^^ method not found in `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>` + | + ::: $SRC_DIR/libcore/iter/adapters/mod.rs:LL:COL + | +LL | pub struct Cloned { + | -------------------- doesn't satisfy `_: std::iter::Iterator` +... +LL | pub struct TakeWhile { + | -------------------------- doesn't satisfy `<_ as std::iter::Iterator>::Item = &_` | = note: the method `collect` exists but the following trait bounds were not satisfied: - `&mut std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>> : std::iter::Iterator` - `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>> : std::iter::Iterator` + `, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]> as std::iter::Iterator>::Item = &_` + which is required by `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` + `std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` + which is required by `&mut std::iter::Cloned, [closure@$DIR/issue-31173.rs:10:39: 13:6 found_e:_]>>: std::iter::Iterator` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-33504.stderr b/src/test/ui/issues/issue-33504.stderr index 522df6a07c2..1e61178f42e 100644 --- a/src/test/ui/issues/issue-33504.stderr +++ b/src/test/ui/issues/issue-33504.stderr @@ -1,8 +1,15 @@ error[E0308]: mismatched types --> $DIR/issue-33504.rs:7:13 | +LL | struct Test; + | ------------ unit struct defined here +... LL | let Test = 1; - | ^^^^ expected integer, found struct `Test` + | ^^^^ + | | + | expected integer, found struct `Test` + | `Test` is interpreted as a unit struct, not a new binding + | help: introduce a new binding instead: `other_test` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-35668.stderr b/src/test/ui/issues/issue-35668.stderr index 9d5796a5eef..98e8e6366b9 100644 --- a/src/test/ui/issues/issue-35668.stderr +++ b/src/test/ui/issues/issue-35668.stderr @@ -5,8 +5,6 @@ LL | a.iter().map(|a| a*a) | -^- &T | | | &T - | - = note: an implementation of `std::ops::Mul` might be missing for `&T` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-35677.stderr b/src/test/ui/issues/issue-35677.stderr index a998f95d306..978221e502f 100644 --- a/src/test/ui/issues/issue-35677.stderr +++ b/src/test/ui/issues/issue-35677.stderr @@ -5,8 +5,8 @@ LL | this.is_subset(other) | ^^^^^^^^^ method not found in `&std::collections::HashSet` | = note: the method `is_subset` exists but the following trait bounds were not satisfied: - `T : std::cmp::Eq` - `T : std::hash::Hash` + `T: std::cmp::Eq` + `T: std::hash::Hash` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-37026.stderr b/src/test/ui/issues/issue-37026.stderr index 361369e68bc..f0285730c5a 100644 --- a/src/test/ui/issues/issue-37026.stderr +++ b/src/test/ui/issues/issue-37026.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/issue-37026.rs:6:9 | LL | let empty_struct::XEmpty2 = (); - | ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `empty_struct::XEmpty2` + | ^^^^^^^^^^^^^^^^^^^^^ -- this expression has type `()` + | | + | expected `()`, found struct `empty_struct::XEmpty2` error[E0308]: mismatched types --> $DIR/issue-37026.rs:7:9 diff --git a/src/test/ui/issues/issue-3763.rs b/src/test/ui/issues/issue-3763.rs index 5d17a30ab36..451321c5503 100644 --- a/src/test/ui/issues/issue-3763.rs +++ b/src/test/ui/issues/issue-3763.rs @@ -1,3 +1,6 @@ +// compile-flags: -Zsave-analysis +// Also regression test for #69416 + mod my_mod { pub struct MyStruct { priv_field: isize @@ -18,9 +21,9 @@ fn main() { let _woohoo = (Box::new(my_struct)).priv_field; //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private - (&my_struct).happyfun(); //~ ERROR method `happyfun` is private + (&my_struct).happyfun(); //~ ERROR associated function `happyfun` is private - (Box::new(my_struct)).happyfun(); //~ ERROR method `happyfun` is private + (Box::new(my_struct)).happyfun(); //~ ERROR associated function `happyfun` is private let nope = my_struct.priv_field; //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private } diff --git a/src/test/ui/issues/issue-3763.stderr b/src/test/ui/issues/issue-3763.stderr index 50169286b1c..d548477a88f 100644 --- a/src/test/ui/issues/issue-3763.stderr +++ b/src/test/ui/issues/issue-3763.stderr @@ -1,29 +1,29 @@ error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private - --> $DIR/issue-3763.rs:15:19 + --> $DIR/issue-3763.rs:18:19 | LL | let _woohoo = (&my_struct).priv_field; | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private - --> $DIR/issue-3763.rs:18:19 + --> $DIR/issue-3763.rs:21:19 | LL | let _woohoo = (Box::new(my_struct)).priv_field; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0624]: method `happyfun` is private - --> $DIR/issue-3763.rs:21:18 +error[E0624]: associated function `happyfun` is private + --> $DIR/issue-3763.rs:24:18 | LL | (&my_struct).happyfun(); | ^^^^^^^^ -error[E0624]: method `happyfun` is private - --> $DIR/issue-3763.rs:23:27 +error[E0624]: associated function `happyfun` is private + --> $DIR/issue-3763.rs:26:27 | LL | (Box::new(my_struct)).happyfun(); | ^^^^^^^^ error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private - --> $DIR/issue-3763.rs:24:16 + --> $DIR/issue-3763.rs:27:16 | LL | let nope = my_struct.priv_field; | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-39848.rs b/src/test/ui/issues/issue-39848.rs index 5d1db7be857..1964d739989 100644 --- a/src/test/ui/issues/issue-39848.rs +++ b/src/test/ui/issues/issue-39848.rs @@ -1,10 +1,9 @@ macro_rules! get_opt { ($tgt:expr, $field:ident) => { - if $tgt.has_$field() {} + if $tgt.has_$field() {} //~ ERROR expected `{`, found `foo` } } fn main() { get_opt!(bar, foo); - //~^ ERROR expected `{`, found `foo` } diff --git a/src/test/ui/issues/issue-39848.stderr b/src/test/ui/issues/issue-39848.stderr index 11b145d6e0d..0250c6b1fdd 100644 --- a/src/test/ui/issues/issue-39848.stderr +++ b/src/test/ui/issues/issue-39848.stderr @@ -1,13 +1,17 @@ error: expected `{`, found `foo` - --> $DIR/issue-39848.rs:8:19 + --> $DIR/issue-39848.rs:3:21 | LL | if $tgt.has_$field() {} - | -- -- help: try placing this code inside a block: `{ () }` - | | + | -- ^^^^^^-- + | | | + | | expected `{` + | | help: try placing this code inside a block: `{ $field() }` | this `if` expression has a condition, but no block ... LL | get_opt!(bar, foo); - | ^^^ expected `{` + | ------------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40610.stderr b/src/test/ui/issues/issue-40610.stderr index 95f45c168e1..b4e302dfffc 100644 --- a/src/test/ui/issues/issue-40610.stderr +++ b/src/test/ui/issues/issue-40610.stderr @@ -5,8 +5,6 @@ LL | () + f(&[1.0]); | -- ^ --------- () | | | () - | - = note: an implementation of `std::ops::Add` might be missing for `()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41394.stderr b/src/test/ui/issues/issue-41394.stderr index 3f60ea4bbf7..47a24547d45 100644 --- a/src/test/ui/issues/issue-41394.stderr +++ b/src/test/ui/issues/issue-41394.stderr @@ -5,8 +5,6 @@ LL | A = "" + 1 | -- ^ - {integer} | | | &str - | - = note: an implementation of `std::ops::Add` might be missing for `&str` error[E0080]: evaluation of constant value failed --> $DIR/issue-41394.rs:7:9 diff --git a/src/test/ui/issues/issue-4935.rs b/src/test/ui/issues/issue-4935.rs index 3b258c35682..b342bbb1b8e 100644 --- a/src/test/ui/issues/issue-4935.rs +++ b/src/test/ui/issues/issue-4935.rs @@ -3,4 +3,4 @@ fn foo(a: usize) {} //~^ defined here fn main() { foo(5, 6) } -//~^ ERROR this function takes 1 parameter but 2 parameters were supplied +//~^ ERROR this function takes 1 argument but 2 arguments were supplied diff --git a/src/test/ui/issues/issue-4935.stderr b/src/test/ui/issues/issue-4935.stderr index a99581fdca1..0cc686e1cf8 100644 --- a/src/test/ui/issues/issue-4935.stderr +++ b/src/test/ui/issues/issue-4935.stderr @@ -1,11 +1,13 @@ -error[E0061]: this function takes 1 parameter but 2 parameters were supplied +error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/issue-4935.rs:5:13 | LL | fn foo(a: usize) {} | ---------------- defined here LL | LL | fn main() { foo(5, 6) } - | ^^^^^^^^^ expected 1 parameter + | ^^^ - - supplied 2 arguments + | | + | expected 1 argument error: aborting due to previous error diff --git a/src/test/ui/issues/issue-4968.stderr b/src/test/ui/issues/issue-4968.stderr index 35435d0e618..5451cf42355 100644 --- a/src/test/ui/issues/issue-4968.stderr +++ b/src/test/ui/issues/issue-4968.stderr @@ -1,8 +1,15 @@ error[E0308]: mismatched types --> $DIR/issue-4968.rs:5:16 | +LL | const A: (isize,isize) = (4,2); + | ------------------------------- constant defined here +LL | fn main() { LL | match 42 { A => () } - | ^ expected integer, found tuple + | ^ + | | + | expected integer, found tuple + | `A` is interpreted as a constant, not a new binding + | help: introduce a new binding instead: `other_a` | = note: expected type `{integer}` found tuple `(isize, isize)` diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr index f91f6e891ed..b97131a1992 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr @@ -2,10 +2,11 @@ error[E0599]: no method named `as_deref` found for enum `std::option::Option<{in --> $DIR/option-as_deref.rs:2:29 | LL | let _result = &Some(42).as_deref(); - | ^^^^^^^^ help: there is a method with a similar name: `as_ref` + | ^^^^^^^^ help: there is an associated function with a similar name: `as_ref` | = note: the method `as_deref` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::Deref` + `{integer}: std::ops::Deref` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr index 583236345ca..f2133c8c84d 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr @@ -5,7 +5,8 @@ LL | let _result = &mut Some(42).as_deref_mut(); | ^^^^^^^^^^^^ method not found in `std::option::Option<{integer}>` | = note: the method `as_deref_mut` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::DerefMut` + `{integer}: std::ops::DerefMut` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr index fae11fe62b1..f33e9c7823e 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr @@ -2,10 +2,11 @@ error[E0599]: no method named `as_deref` found for enum `std::result::Result<{in --> $DIR/result-as_deref.rs:4:27 | LL | let _result = &Ok(42).as_deref(); - | ^^^^^^^^ help: there is a method with a similar name: `as_ref` + | ^^^^^^^^ help: there is an associated function with a similar name: `as_ref` | = note: the method `as_deref` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::Deref` + `{integer}: std::ops::Deref` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr index 1d98361c461..68ebfab95c4 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_err.stderr @@ -2,10 +2,11 @@ error[E0599]: no method named `as_deref_err` found for enum `std::result::Result --> $DIR/result-as_deref_err.rs:4:28 | LL | let _result = &Err(41).as_deref_err(); - | ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut` + | ^^^^^^^^^^^^ help: there is an associated function with a similar name: `as_deref_mut` | = note: the method `as_deref_err` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::Deref` + `{integer}: std::ops::Deref` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr index 2c6231fb3b5..d2ba1049b76 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr @@ -2,10 +2,11 @@ error[E0599]: no method named `as_deref_mut` found for enum `std::result::Result --> $DIR/result-as_deref_mut.rs:4:31 | LL | let _result = &mut Ok(42).as_deref_mut(); - | ^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_err` + | ^^^^^^^^^^^^ help: there is an associated function with a similar name: `as_deref_err` | = note: the method `as_deref_mut` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::DerefMut` + `{integer}: std::ops::DerefMut` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr index 950a050ea9f..d724ae5c74b 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut_err.stderr @@ -2,10 +2,11 @@ error[E0599]: no method named `as_deref_mut_err` found for enum `std::result::Re --> $DIR/result-as_deref_mut_err.rs:4:32 | LL | let _result = &mut Err(41).as_deref_mut_err(); - | ^^^^^^^^^^^^^^^^ help: there is a method with a similar name: `as_deref_mut` + | ^^^^^^^^^^^^^^^^ help: there is an associated function with a similar name: `as_deref_mut` | = note: the method `as_deref_mut_err` exists but the following trait bounds were not satisfied: - `{integer} : std::ops::DerefMut` + `{integer}: std::ops::DerefMut` + `<{integer} as std::ops::Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5100.stderr b/src/test/ui/issues/issue-5100.stderr index c47e8689436..a89980964ca 100644 --- a/src/test/ui/issues/issue-5100.stderr +++ b/src/test/ui/issues/issue-5100.stderr @@ -1,6 +1,11 @@ error[E0308]: mismatched types --> $DIR/issue-5100.rs:8:9 | +LL | enum A { B, C } + | - unit variant defined here +... +LL | match (true, false) { + | ------------- this expression has type `(bool, bool)` LL | A::B => (), | ^^^^ expected tuple, found enum `A` | @@ -10,6 +15,8 @@ LL | A::B => (), error[E0308]: mismatched types --> $DIR/issue-5100.rs:17:9 | +LL | match (true, false) { + | ------------- this expression has type `(bool, bool)` LL | (true, false, false) => () | ^^^^^^^^^^^^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements | @@ -19,6 +26,8 @@ LL | (true, false, false) => () error[E0308]: mismatched types --> $DIR/issue-5100.rs:25:9 | +LL | match (true, false) { + | ------------- this expression has type `(bool, bool)` LL | (true, false, false) => () | ^^^^^^^^^^^^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements | @@ -39,6 +48,8 @@ LL | box (true, false) => () error[E0308]: mismatched types --> $DIR/issue-5100.rs:40:9 | +LL | match (true, false) { + | ------------- this expression has type `(bool, bool)` LL | &(true, false) => () | ^^^^^^^^^^^^^^ expected tuple, found reference | diff --git a/src/test/ui/issues/issue-5153.stderr b/src/test/ui/issues/issue-5153.stderr index 4680c8b131c..93aaf4b9d82 100644 --- a/src/test/ui/issues/issue-5153.stderr +++ b/src/test/ui/issues/issue-5153.stderr @@ -1,12 +1,11 @@ error[E0599]: no method named `foo` found for reference `&dyn Foo` in the current scope --> $DIR/issue-5153.rs:10:27 | +LL | fn foo(self: Box); + | --------- the method might not be found because of this arbitrary self type +... LL | (&5isize as &dyn Foo).foo(); | ^^^ method not found in `&dyn Foo` - | - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `foo`, perhaps you need to implement it: - candidate #1: `Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-51798.rs b/src/test/ui/issues/issue-51798.rs new file mode 100644 index 00000000000..b075809e93a --- /dev/null +++ b/src/test/ui/issues/issue-51798.rs @@ -0,0 +1,14 @@ +// edition:2018 +// aux-build:issue-51798.rs +// check-pass + +extern crate issue_51798; + +mod server { + fn f() { + let mut v = issue_51798::vec(); + v.clear(); + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-53498.rs b/src/test/ui/issues/issue-53498.rs index c87d4236492..9e0437c46f4 100644 --- a/src/test/ui/issues/issue-53498.rs +++ b/src/test/ui/issues/issue-53498.rs @@ -13,5 +13,5 @@ pub mod test { } fn main() { - test::Foo::::foo(); //~ ERROR method `foo` is private + test::Foo::::foo(); //~ ERROR associated function `foo` is private } diff --git a/src/test/ui/issues/issue-53498.stderr b/src/test/ui/issues/issue-53498.stderr index 3fd48233dae..042848c27bb 100644 --- a/src/test/ui/issues/issue-53498.stderr +++ b/src/test/ui/issues/issue-53498.stderr @@ -1,4 +1,4 @@ -error[E0624]: method `foo` is private +error[E0624]: associated function `foo` is private --> $DIR/issue-53498.rs:16:5 | LL | test::Foo::::foo(); diff --git a/src/test/ui/issues/issue-54348.rs b/src/test/ui/issues/issue-54348.rs index fd9a9e024aa..5c38d7c42f6 100644 --- a/src/test/ui/issues/issue-54348.rs +++ b/src/test/ui/issues/issue-54348.rs @@ -2,6 +2,6 @@ fn main() { [1][0u64 as usize]; - [1][1.5 as usize]; //~ ERROR index out of bounds - [1][1u64 as usize]; //~ ERROR index out of bounds + [1][1.5 as usize]; //~ ERROR operation will panic + [1][1u64 as usize]; //~ ERROR operation will panic } diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr index 7619cd7437e..6b67125e36c 100644 --- a/src/test/ui/issues/issue-54348.stderr +++ b/src/test/ui/issues/issue-54348.stderr @@ -1,16 +1,16 @@ -error: index out of bounds: the len is 1 but the index is 1 +error: this operation will panic at runtime --> $DIR/issue-54348.rs:5:5 | LL | [1][1.5 as usize]; - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 | - = note: `#[deny(const_err)]` on by default + = note: `#[deny(unconditional_panic)]` on by default -error: index out of bounds: the len is 1 but the index is 1 +error: this operation will panic at runtime --> $DIR/issue-54348.rs:6:5 | LL | [1][1u64 as usize]; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-55587.stderr b/src/test/ui/issues/issue-55587.stderr index bb0d15a23d6..faf78cfe8d9 100644 --- a/src/test/ui/issues/issue-55587.stderr +++ b/src/test/ui/issues/issue-55587.stderr @@ -1,4 +1,4 @@ -error[E0164]: expected tuple struct or tuple variant, found method `Path::new` +error[E0164]: expected tuple struct or tuple variant, found associated function `Path::new` --> $DIR/issue-55587.rs:4:9 | LL | let Path::new(); diff --git a/src/test/ui/issues/issue-57362-1.stderr b/src/test/ui/issues/issue-57362-1.stderr index ad596db13cc..5c611cd43d3 100644 --- a/src/test/ui/issues/issue-57362-1.stderr +++ b/src/test/ui/issues/issue-57362-1.stderr @@ -6,8 +6,11 @@ LL | a.f(); | = note: `a` is a function, perhaps you wish to call it = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `f`, perhaps you need to implement it: - candidate #1: `Trait` +note: `Trait` defines an item `f`, perhaps you need to implement it + --> $DIR/issue-57362-1.rs:8:1 + | +LL | trait Trait { + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-57362-2.stderr b/src/test/ui/issues/issue-57362-2.stderr index 3528084f6ce..2edc0097464 100644 --- a/src/test/ui/issues/issue-57362-2.stderr +++ b/src/test/ui/issues/issue-57362-2.stderr @@ -5,8 +5,11 @@ LL | let x = ::make_g(); | ^^^^^^ function or associated item not found in `for<'r> fn(&'r ())` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `make_g`, perhaps you need to implement it: - candidate #1: `X` +note: `X` defines an item `make_g`, perhaps you need to implement it + --> $DIR/issue-57362-2.rs:8:1 + | +LL | trait X { + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr index 0ea6b017548..a8db8e8b41a 100644 --- a/src/test/ui/issues/issue-58856-1.stderr +++ b/src/test/ui/issues/issue-58856-1.stderr @@ -9,8 +9,14 @@ LL | fn b(self> error: expected `;` or `{`, found `>` --> $DIR/issue-58856-1.rs:3:14 | +LL | impl A { + | - while parsing this item list starting here +LL | LL | fn b(self> | ^ expected `;` or `{` +... +LL | } + | - the item list ends here error[E0412]: cannot find type `A` in this scope --> $DIR/issue-58856-1.rs:1:6 diff --git a/src/test/ui/issues/issue-58856-2.rs b/src/test/ui/issues/issue-58856-2.rs index 745f0300bd5..9356d57b0e5 100644 --- a/src/test/ui/issues/issue-58856-2.rs +++ b/src/test/ui/issues/issue-58856-2.rs @@ -9,6 +9,6 @@ impl Howness for () { Empty } } -//~^ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, +//~^ ERROR non-item in item list fn main() {} diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr index 01d70d861e2..303b5eacc32 100644 --- a/src/test/ui/issues/issue-58856-2.stderr +++ b/src/test/ui/issues/issue-58856-2.stderr @@ -7,13 +7,17 @@ LL | fn how_are_you(&self -> Empty { | | help: `)` may belong here | unclosed delimiter -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `)` +error: non-item in item list --> $DIR/issue-58856-2.rs:11:1 | -LL | } - | - expected one of 10 possible tokens +LL | impl Howness for () { + | - item list starts here +... LL | } - | ^ unexpected token + | ^ + | | + | non-item starts here + | item list ends here error[E0407]: method `how_are_you` is not a member of trait `Howness` --> $DIR/issue-58856-2.rs:6:5 diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/issues/issue-59488.stderr index 2ac5577e0a0..58f1376b19d 100644 --- a/src/test/ui/issues/issue-59488.stderr +++ b/src/test/ui/issues/issue-59488.stderr @@ -58,8 +58,6 @@ LL | foo > bar; | --- ^ --- fn(i64) -> i64 {bar} | | | fn() -> i32 {foo} - | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() -> i32 {foo}` error[E0308]: mismatched types --> $DIR/issue-59488.rs:25:11 @@ -79,7 +77,6 @@ LL | assert_eq!(Foo::Bar, i); | fn(usize) -> Foo {Foo::Bar} | fn(usize) -> Foo {Foo::Bar} | - = note: an implementation of `std::cmp::PartialEq` might be missing for `fn(usize) -> Foo {Foo::Bar}` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` diff --git a/src/test/ui/issues/issue-60075.rs b/src/test/ui/issues/issue-60075.rs index 1323f646be8..e89d78ee8a6 100644 --- a/src/test/ui/issues/issue-60075.rs +++ b/src/test/ui/issues/issue-60075.rs @@ -4,7 +4,8 @@ trait T { fn qux() -> Option { let _ = if true { }); -//~^ ERROR expected one of `async` -//~| ERROR expected one of `.`, `;`, `?`, `else`, or an operator, found `}` +//~^ ERROR non-item in item list +//~| ERROR mismatched closing delimiter: `)` +//~| ERROR expected one of `.`, `;` Some(4) } diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr index 60eb99b46b7..e3b7f4ad420 100644 --- a/src/test/ui/issues/issue-60075.stderr +++ b/src/test/ui/issues/issue-60075.stderr @@ -4,14 +4,26 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}` LL | }); | ^ expected one of `.`, `;`, `?`, `else`, or an operator -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `;` +error: non-item in item list --> $DIR/issue-60075.rs:6:11 | +LL | trait T { + | - item list starts here +... +LL | }); + | ^ non-item starts here +... +LL | } + | - item list ends here + +error: mismatched closing delimiter: `)` + --> $DIR/issue-60075.rs:6:10 + | LL | fn qux() -> Option { | - unclosed delimiter LL | let _ = if true { LL | }); - | ^ help: `}` may belong here + | ^ mismatched closing delimiter -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-63364.stderr b/src/test/ui/issues/issue-63364.stderr index 60ff318f35a..0375359aeab 100644 --- a/src/test/ui/issues/issue-63364.stderr +++ b/src/test/ui/issues/issue-63364.stderr @@ -5,6 +5,7 @@ LL | for n in 100_000.. { | ^^^^^^^ | = note: `#[deny(overflowing_literals)]` on by default + = note: the literal `100_000` does not fit into the type `u16` whose range is `0..=65535` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-6596-1.rs b/src/test/ui/issues/issue-6596-1.rs index 5da54451346..25f1d650072 100644 --- a/src/test/ui/issues/issue-6596-1.rs +++ b/src/test/ui/issues/issue-6596-1.rs @@ -1,7 +1,7 @@ macro_rules! e { ($inp:ident) => ( $nonexistent - //~^ ERROR unknown macro variable `nonexistent` + //~^ ERROR expected expression, found `$` ); } diff --git a/src/test/ui/issues/issue-6596-1.stderr b/src/test/ui/issues/issue-6596-1.stderr index 4f29d8a9274..216fe6472a5 100644 --- a/src/test/ui/issues/issue-6596-1.stderr +++ b/src/test/ui/issues/issue-6596-1.stderr @@ -1,8 +1,8 @@ -error: unknown macro variable `nonexistent` +error: expected expression, found `$` --> $DIR/issue-6596-1.rs:3:9 | LL | $nonexistent - | ^^^^^^^^^^^^ unknown macro variable + | ^^^^^^^^^^^^ expected expression ... LL | e!(foo); | -------- in this macro invocation diff --git a/src/test/ui/issues/issue-6596-2.rs b/src/test/ui/issues/issue-6596-2.rs index b19700efe5a..8f7c98d9a67 100644 --- a/src/test/ui/issues/issue-6596-2.rs +++ b/src/test/ui/issues/issue-6596-2.rs @@ -3,7 +3,7 @@ macro_rules! g { ($inp:ident) => ( { $inp $nonexistent } - //~^ ERROR unknown macro variable `nonexistent` + //~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `$` ); } diff --git a/src/test/ui/issues/issue-6596-2.stderr b/src/test/ui/issues/issue-6596-2.stderr index 4fcb0176faa..3d13c64f762 100644 --- a/src/test/ui/issues/issue-6596-2.stderr +++ b/src/test/ui/issues/issue-6596-2.stderr @@ -1,8 +1,8 @@ -error: unknown macro variable `nonexistent` +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `$` --> $DIR/issue-6596-2.rs:5:16 | LL | { $inp $nonexistent } - | ^^^^^^^^^^^^ unknown macro variable + | ^^^^^^^^^^^^ expected one of 8 possible tokens ... LL | g!(foo); | -------- in this macro invocation diff --git a/src/test/ui/issues/issue-66473.rs b/src/test/ui/issues/issue-66473.rs index cc298a28b97..9db4521bb42 100644 Binary files a/src/test/ui/issues/issue-66473.rs and b/src/test/ui/issues/issue-66473.rs differ diff --git a/src/test/ui/issues/issue-66473.stderr b/src/test/ui/issues/issue-66473.stderr index dbeef44bad0..b370b125cfe 100644 Binary files a/src/test/ui/issues/issue-66473.stderr and b/src/test/ui/issues/issue-66473.stderr differ diff --git a/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs b/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs new file mode 100644 index 00000000000..6e030f1cc48 --- /dev/null +++ b/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs @@ -0,0 +1,33 @@ +// run-fail +// compile-flags: -C opt-level=3 +// error-pattern: index out of bounds: the len is 0 but the index is 16777216 +// ignore-wasm no panic or subprocess support +// ignore-emscripten no panic or subprocess support + +fn do_test(x: usize) { + let mut arr = vec![vec![0u8; 3]]; + + let mut z = vec![0]; + for arr_ref in arr.iter_mut() { + for y in 0..x { + for _ in 0..1 { + z.reserve_exact(x); + let iterator = std::iter::repeat(0).take(x); + let mut cnt = 0; + iterator.for_each(|_| { + z[0] = 0; + cnt += 1; + }); + let a = y * x; + let b = (y + 1) * x - 1; + let slice = &mut arr_ref[a..b]; + slice[1 << 24] += 1; + } + } + } +} + +fn main() { + do_test(1); + do_test(2); +} diff --git a/src/test/ui/issues/issue-69225-layout-repeated-checked-add.rs b/src/test/ui/issues/issue-69225-layout-repeated-checked-add.rs new file mode 100644 index 00000000000..7f43e4d1a51 --- /dev/null +++ b/src/test/ui/issues/issue-69225-layout-repeated-checked-add.rs @@ -0,0 +1,31 @@ +// Ensure we appropriately error instead of overflowing a calculation when creating a new Alloc +// Layout + +// run-fail +// compile-flags: -C opt-level=3 +// error-pattern: index out of bounds: the len is 0 but the index is 16777216 +// ignore-wasm no panic or subprocess support +// ignore-emscripten no panic or subprocess support + +fn do_test(x: usize) { + let arr = vec![vec![0u8; 3]]; + + let mut z = Vec::new(); + for arr_ref in arr { + for y in 0..x { + for _ in 0..1 { + z.extend(std::iter::repeat(0).take(x)); + let a = y * x; + let b = (y + 1) * x - 1; + let slice = &arr_ref[a..b]; + eprintln!("{} {} {} {}", a, b, arr_ref.len(), slice.len()); + eprintln!("{:?}", slice[1 << 24]); + } + } + } +} + +fn main() { + do_test(1); + do_test(2); +} diff --git a/src/test/ui/issues/issue-69306.rs b/src/test/ui/issues/issue-69306.rs new file mode 100644 index 00000000000..85d60952ac8 --- /dev/null +++ b/src/test/ui/issues/issue-69306.rs @@ -0,0 +1,45 @@ +fn main() {} + +struct S0(T); +impl S0 { + const C: S0 = Self(0); + //~^ ERROR mismatched types + //~| ERROR mismatched types + + fn foo() { + Self(0); + //~^ ERROR mismatched types + } +} + +// Testing normalization. +trait Fun { + type Out; +} +impl Fun for S0 { + type Out = Self; +} +trait Foo { + fn foo(); +} +impl Foo for as Fun>::Out { + fn foo() { + Self(0); //~ ERROR mismatched types + } +} + +struct S1(T, U); +impl S1 { + const C: S1 = Self(0, 1); + //~^ ERROR mismatched types + //~| ERROR mismatched types +} + +struct S2(T); +impl S2 { + fn map(x: U) -> S2 { + Self(x) + //~^ ERROR mismatched types + //~| ERROR mismatched types + } +} diff --git a/src/test/ui/issues/issue-69306.stderr b/src/test/ui/issues/issue-69306.stderr new file mode 100644 index 00000000000..a2a42739ca8 --- /dev/null +++ b/src/test/ui/issues/issue-69306.stderr @@ -0,0 +1,115 @@ +error[E0308]: mismatched types + --> $DIR/issue-69306.rs:5:28 + | +LL | impl S0 { + | - this type parameter +LL | const C: S0 = Self(0); + | ^ expected type parameter `T`, found integer + | + = note: expected type parameter `T` + found type `{integer}` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error[E0308]: mismatched types + --> $DIR/issue-69306.rs:5:23 + | +LL | impl S0 { + | - this type parameter +LL | const C: S0 = Self(0); + | ^^^^^^^ expected `u8`, found type parameter `T` + | + = note: expected struct `S0` + found struct `S0` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error[E0308]: mismatched types + --> $DIR/issue-69306.rs:10:14 + | +LL | impl S0 { + | - this type parameter +... +LL | Self(0); + | ^ expected type parameter `T`, found integer + | + = note: expected type parameter `T` + found type `{integer}` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error[E0308]: mismatched types + --> $DIR/issue-69306.rs:27:14 + | +LL | impl Foo for as Fun>::Out { + | - this type parameter +LL | fn foo() { +LL | Self(0); + | ^ expected type parameter `T`, found integer + | + = note: expected type parameter `T` + found type `{integer}` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error[E0308]: mismatched types + --> $DIR/issue-69306.rs:33:32 + | +LL | impl S1 { + | - this type parameter +LL | const C: S1 = Self(0, 1); + | ^ expected type parameter `T`, found integer + | + = note: expected type parameter `T` + found type `{integer}` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error[E0308]: mismatched types + --> $DIR/issue-69306.rs:33:27 + | +LL | impl S1 { + | - this type parameter +LL | const C: S1 = Self(0, 1); + | ^^^^^^^^^^ expected `u8`, found type parameter `T` + | + = note: expected struct `S1` + found struct `S1` + = help: type parameters must be constrained to match other types + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error[E0308]: mismatched types + --> $DIR/issue-69306.rs:41:14 + | +LL | impl S2 { + | - expected type parameter +LL | fn map(x: U) -> S2 { + | - found type parameter +LL | Self(x) + | ^ expected type parameter `T`, found type parameter `U` + | + = note: expected type parameter `T` + found type parameter `U` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error[E0308]: mismatched types + --> $DIR/issue-69306.rs:41:9 + | +LL | impl S2 { + | - found type parameter +LL | fn map(x: U) -> S2 { + | - ----- expected `S2` because of return type + | | + | expected type parameter +LL | Self(x) + | ^^^^^^^ expected type parameter `U`, found type parameter `T` + | + = note: expected struct `S2` + found struct `S2` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-69396-const-no-type-in-macro.rs b/src/test/ui/issues/issue-69396-const-no-type-in-macro.rs new file mode 100644 index 00000000000..69fc0c1cbb9 --- /dev/null +++ b/src/test/ui/issues/issue-69396-const-no-type-in-macro.rs @@ -0,0 +1,17 @@ +macro_rules! suite { + ( $( $fn:ident; )* ) => { + $( + const A = "A".$fn(); + //~^ ERROR the name `A` is defined multiple times + //~| ERROR missing type for `const` item + //~| ERROR the type placeholder `_` is not allowed within types + )* + } +} + +suite! { + len; + is_empty; +} + +fn main() {} diff --git a/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr b/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr new file mode 100644 index 00000000000..1af5368d2b6 --- /dev/null +++ b/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr @@ -0,0 +1,53 @@ +error[E0428]: the name `A` is defined multiple times + --> $DIR/issue-69396-const-no-type-in-macro.rs:4:13 + | +LL | const A = "A".$fn(); + | ^^^^^^^^^^^^^^^^^^^^ + | | + | `A` redefined here + | previous definition of the value `A` here +... +LL | / suite! { +LL | | len; +LL | | is_empty; +LL | | } + | |_- in this macro invocation + | + = note: `A` must be defined only once in the value namespace of this module + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: missing type for `const` item + --> $DIR/issue-69396-const-no-type-in-macro.rs:4:19 + | +LL | const A = "A".$fn(); + | ^ help: provide a type for the item: `A: usize` +... +LL | / suite! { +LL | | len; +LL | | is_empty; +LL | | } + | |_- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-69396-const-no-type-in-macro.rs:4:19 + | +LL | const A = "A".$fn(); + | ^ + | | + | not allowed in type signatures + | help: replace `_` with the correct type: `bool` +... +LL | / suite! { +LL | | len; +LL | | is_empty; +LL | | } + | |_- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0121, E0428. +For more information about an error, try `rustc --explain E0121`. diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs new file mode 100644 index 00000000000..d060f26fb2a --- /dev/null +++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.rs @@ -0,0 +1,23 @@ +trait TraitA { + const VALUE: usize; +} + +struct A; +impl TraitA for A { + const VALUE: usize = 0; +} + +trait TraitB { + type MyA: TraitA; + const VALUE: usize = Self::MyA::VALUE; +} + +struct B; +impl TraitB for B { //~ ERROR not all trait items implemented, missing: `MyA` + type M = A; //~ ERROR type `M` is not a member of trait `TraitB` +} + +fn main() { + let _ = [0; B::VALUE]; + //~^ ERROR array lengths can't depend on generic parameters +} diff --git a/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr new file mode 100644 index 00000000000..c6b2b4d27a2 --- /dev/null +++ b/src/test/ui/issues/issue-69602-type-err-during-codegen-ice.stderr @@ -0,0 +1,25 @@ +error[E0437]: type `M` is not a member of trait `TraitB` + --> $DIR/issue-69602-type-err-during-codegen-ice.rs:17:5 + | +LL | type M = A; + | ^^^^^^^^^^^^^ not a member of trait `TraitB` + +error[E0046]: not all trait items implemented, missing: `MyA` + --> $DIR/issue-69602-type-err-during-codegen-ice.rs:16:1 + | +LL | type MyA: TraitA; + | ----------------- `MyA` from trait +... +LL | impl TraitB for B { + | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation + +error: array lengths can't depend on generic parameters + --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17 + | +LL | let _ = [0; B::VALUE]; + | ^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0046, E0437. +For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/issues/issue-69725.rs b/src/test/ui/issues/issue-69725.rs new file mode 100644 index 00000000000..b8130b41f21 --- /dev/null +++ b/src/test/ui/issues/issue-69725.rs @@ -0,0 +1,11 @@ +// aux-build:issue-69725.rs + +extern crate issue_69725; +use issue_69725::Struct; + +fn crash() { + let _ = Struct::::new().clone(); + //~^ ERROR: no method named `clone` found +} + +fn main() {} diff --git a/src/test/ui/issues/issue-69725.stderr b/src/test/ui/issues/issue-69725.stderr new file mode 100644 index 00000000000..667383e072a --- /dev/null +++ b/src/test/ui/issues/issue-69725.stderr @@ -0,0 +1,18 @@ +error[E0599]: no method named `clone` found for struct `issue_69725::Struct` in the current scope + --> $DIR/issue-69725.rs:7:32 + | +LL | let _ = Struct::::new().clone(); + | ^^^^^ method not found in `issue_69725::Struct` + | + ::: $DIR/auxiliary/issue-69725.rs:2:1 + | +LL | pub struct Struct(A); + | ------------------------ doesn't satisfy `issue_69725::Struct: std::clone::Clone` + | + = note: the method `clone` exists but the following trait bounds were not satisfied: + `A: std::clone::Clone` + which is required by `issue_69725::Struct: std::clone::Clone` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/issues/issue-7867.stderr b/src/test/ui/issues/issue-7867.stderr index 58e82facf80..0d3121d6045 100644 --- a/src/test/ui/issues/issue-7867.stderr +++ b/src/test/ui/issues/issue-7867.stderr @@ -1,6 +1,11 @@ error[E0308]: mismatched types --> $DIR/issue-7867.rs:7:9 | +LL | enum A { B, C } + | - unit variant defined here +... +LL | match (true, false) { + | ------------- this expression has type `(bool, bool)` LL | A::B => (), | ^^^^ expected tuple, found enum `A` | diff --git a/src/test/ui/issues/issue-8460-const.noopt.stderr b/src/test/ui/issues/issue-8460-const.noopt.stderr new file mode 100644 index 00000000000..3556ec08247 --- /dev/null +++ b/src/test/ui/issues/issue-8460-const.noopt.stderr @@ -0,0 +1,150 @@ +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:14:36 + | +LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^^^ attempt to divide with overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:16:36 + | +LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:18:36 + | +LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:20:36 + | +LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:22:36 + | +LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:24:36 + | +LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^^ attempt to divide with overflow + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:26:36 + | +LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); + | ^^^^^^^^^^ attempt to divide by zero + | + = note: `#[deny(unconditional_panic)]` on by default + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:28:36 + | +LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); + | ^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:30:36 + | +LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:32:36 + | +LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:34:36 + | +LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:36:36 + | +LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); + | ^^^^^^^^^ attempt to divide by zero + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:38:36 + | +LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:40:36 + | +LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:42:36 + | +LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:44:36 + | +LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:46:36 + | +LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:48:36 + | +LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:50:36 + | +LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); + | ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:52:36 + | +LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); + | ^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:54:36 + | +LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:56:36 + | +LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:58:36 + | +LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:60:36 + | +LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); + | ^^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: aborting due to 24 previous errors + diff --git a/src/test/ui/issues/issue-8460-const.opt.stderr b/src/test/ui/issues/issue-8460-const.opt.stderr new file mode 100644 index 00000000000..3556ec08247 --- /dev/null +++ b/src/test/ui/issues/issue-8460-const.opt.stderr @@ -0,0 +1,150 @@ +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:14:36 + | +LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^^^ attempt to divide with overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:16:36 + | +LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:18:36 + | +LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:20:36 + | +LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:22:36 + | +LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:24:36 + | +LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^^ attempt to divide with overflow + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:26:36 + | +LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); + | ^^^^^^^^^^ attempt to divide by zero + | + = note: `#[deny(unconditional_panic)]` on by default + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:28:36 + | +LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); + | ^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:30:36 + | +LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:32:36 + | +LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:34:36 + | +LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:36:36 + | +LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); + | ^^^^^^^^^ attempt to divide by zero + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:38:36 + | +LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:40:36 + | +LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:42:36 + | +LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:44:36 + | +LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:46:36 + | +LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:48:36 + | +LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:50:36 + | +LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); + | ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:52:36 + | +LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); + | ^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:54:36 + | +LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:56:36 + | +LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:58:36 + | +LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:60:36 + | +LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); + | ^^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: aborting due to 24 previous errors + diff --git a/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr b/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr new file mode 100644 index 00000000000..3556ec08247 --- /dev/null +++ b/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr @@ -0,0 +1,150 @@ +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:14:36 + | +LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^^^ attempt to divide with overflow + | + = note: `#[deny(arithmetic_overflow)]` on by default + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:16:36 + | +LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:18:36 + | +LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:20:36 + | +LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:22:36 + | +LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to divide with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:24:36 + | +LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); + | ^^^^^^^^^^^^^^ attempt to divide with overflow + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:26:36 + | +LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); + | ^^^^^^^^^^ attempt to divide by zero + | + = note: `#[deny(unconditional_panic)]` on by default + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:28:36 + | +LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); + | ^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:30:36 + | +LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:32:36 + | +LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:34:36 + | +LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); + | ^^^^^^^^ attempt to divide by zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:36:36 + | +LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); + | ^^^^^^^^^ attempt to divide by zero + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:38:36 + | +LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:40:36 + | +LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:42:36 + | +LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:44:36 + | +LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:46:36 + | +LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this arithmetic operation will overflow + --> $DIR/issue-8460-const.rs:48:36 + | +LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); + | ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:50:36 + | +LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); + | ^^^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:52:36 + | +LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); + | ^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:54:36 + | +LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:56:36 + | +LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:58:36 + | +LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); + | ^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: this operation will panic at runtime + --> $DIR/issue-8460-const.rs:60:36 + | +LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); + | ^^^^^^^^^ attempt to calculate the remainder with a divisor of zero + +error: aborting due to 24 previous errors + diff --git a/src/test/ui/issues/issue-8460-const.rs b/src/test/ui/issues/issue-8460-const.rs index 5866cef2d2c..53005e46d2f 100644 --- a/src/test/ui/issues/issue-8460-const.rs +++ b/src/test/ui/issues/issue-8460-const.rs @@ -1,5 +1,9 @@ +// revisions: noopt opt opt_with_overflow_checks +//[noopt]compile-flags: -C opt-level=0 +//[opt]compile-flags: -O +//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O + // build-fail -// compile-flags: -O #![deny(const_err)] @@ -8,63 +12,51 @@ use std::thread; fn main() { assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero + //~^ ERROR operation will panic assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero + //~^ ERROR operation will panic assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero + //~^ ERROR operation will panic assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero + //~^ ERROR operation will panic assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero + //~^ ERROR operation will panic assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero + //~^ ERROR operation will panic assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - //~| ERROR this expression will panic at runtime + //~^ ERROR arithmetic operation will overflow assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~^ ERROR operation will panic assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~^ ERROR operation will panic assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~^ ERROR operation will panic assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~^ ERROR operation will panic assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~^ ERROR operation will panic assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero + //~^ ERROR operation will panic } diff --git a/src/test/ui/issues/issue-8460-const.stderr b/src/test/ui/issues/issue-8460-const.stderr deleted file mode 100644 index d7373948cb9..00000000000 --- a/src/test/ui/issues/issue-8460-const.stderr +++ /dev/null @@ -1,224 +0,0 @@ -error: attempt to divide with overflow - --> $DIR/issue-8460-const.rs:10:36 - | -LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/issue-8460-const.rs:4:9 - | -LL | #![deny(const_err)] - | ^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:10:36 - | -LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to divide with overflow - -error: attempt to divide with overflow - --> $DIR/issue-8460-const.rs:13:36 - | -LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:13:36 - | -LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to divide with overflow - -error: attempt to divide with overflow - --> $DIR/issue-8460-const.rs:16:36 - | -LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:16:36 - | -LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to divide with overflow - -error: attempt to divide with overflow - --> $DIR/issue-8460-const.rs:19:36 - | -LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:19:36 - | -LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to divide with overflow - -error: attempt to divide with overflow - --> $DIR/issue-8460-const.rs:22:36 - | -LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:22:36 - | -LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to divide with overflow - -error: attempt to divide with overflow - --> $DIR/issue-8460-const.rs:25:36 - | -LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:25:36 - | -LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to divide with overflow - -error: attempt to divide by zero - --> $DIR/issue-8460-const.rs:28:36 - | -LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - | ^^^^^^^^^^ - -error: attempt to divide by zero - --> $DIR/issue-8460-const.rs:30:36 - | -LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - | ^^^^^^^ - -error: attempt to divide by zero - --> $DIR/issue-8460-const.rs:32:36 - | -LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to divide by zero - --> $DIR/issue-8460-const.rs:34:36 - | -LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to divide by zero - --> $DIR/issue-8460-const.rs:36:36 - | -LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to divide by zero - --> $DIR/issue-8460-const.rs:38:36 - | -LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); - | ^^^^^^^^^ - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const.rs:40:36 - | -LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:40:36 - | -LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const.rs:43:36 - | -LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:43:36 - | -LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to calculate the remainder with overflow - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const.rs:46:36 - | -LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:46:36 - | -LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const.rs:49:36 - | -LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:49:36 - | -LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const.rs:52:36 - | -LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:52:36 - | -LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const.rs:55:36 - | -LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ - -error: this expression will panic at runtime - --> $DIR/issue-8460-const.rs:55:36 - | -LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const.rs:58:36 - | -LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - | ^^^^^^^^^^ - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const.rs:60:36 - | -LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - | ^^^^^^^ - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const.rs:62:36 - | -LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const.rs:64:36 - | -LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const.rs:66:36 - | -LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const.rs:68:36 - | -LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); - | ^^^^^^^^^ - -error: aborting due to 36 previous errors - diff --git a/src/test/ui/issues/issue-8460-const2.rs b/src/test/ui/issues/issue-8460-const2.rs deleted file mode 100644 index afea859bb65..00000000000 --- a/src/test/ui/issues/issue-8460-const2.rs +++ /dev/null @@ -1,58 +0,0 @@ -// build-fail -// compile-flags: -C overflow-checks=on -O - -#![deny(const_err)] - -use std::{isize, i8, i16, i32, i64, i128}; -use std::thread; - -fn main() { - assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); - //~^ ERROR attempt to divide with overflow - assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero - assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero - assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero - assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero - assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero - assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); - //~^ ERROR attempt to divide by zero - assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with overflow - assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero - assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero - assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero - assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero - assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero - assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); - //~^ ERROR attempt to calculate the remainder with a divisor of zero -} diff --git a/src/test/ui/issues/issue-8460-const2.stderr b/src/test/ui/issues/issue-8460-const2.stderr deleted file mode 100644 index e25d560fe0c..00000000000 --- a/src/test/ui/issues/issue-8460-const2.stderr +++ /dev/null @@ -1,152 +0,0 @@ -error: attempt to divide with overflow - --> $DIR/issue-8460-const2.rs:10:36 - | -LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/issue-8460-const2.rs:4:9 - | -LL | #![deny(const_err)] - | ^^^^^^^^^ - -error: attempt to divide with overflow - --> $DIR/issue-8460-const2.rs:12:36 - | -LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^ - -error: attempt to divide with overflow - --> $DIR/issue-8460-const2.rs:14:36 - | -LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: attempt to divide with overflow - --> $DIR/issue-8460-const2.rs:16:36 - | -LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: attempt to divide with overflow - --> $DIR/issue-8460-const2.rs:18:36 - | -LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: attempt to divide with overflow - --> $DIR/issue-8460-const2.rs:20:36 - | -LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ - -error: attempt to divide by zero - --> $DIR/issue-8460-const2.rs:22:36 - | -LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - | ^^^^^^^^^^ - -error: attempt to divide by zero - --> $DIR/issue-8460-const2.rs:24:36 - | -LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - | ^^^^^^^ - -error: attempt to divide by zero - --> $DIR/issue-8460-const2.rs:26:36 - | -LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to divide by zero - --> $DIR/issue-8460-const2.rs:28:36 - | -LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to divide by zero - --> $DIR/issue-8460-const2.rs:30:36 - | -LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to divide by zero - --> $DIR/issue-8460-const2.rs:32:36 - | -LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); - | ^^^^^^^^^ - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const2.rs:34:36 - | -LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const2.rs:36:36 - | -LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^ - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const2.rs:38:36 - | -LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const2.rs:40:36 - | -LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const2.rs:42:36 - | -LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ - -error: attempt to calculate the remainder with overflow - --> $DIR/issue-8460-const2.rs:44:36 - | -LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const2.rs:46:36 - | -LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - | ^^^^^^^^^^ - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const2.rs:48:36 - | -LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - | ^^^^^^^ - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const2.rs:50:36 - | -LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const2.rs:52:36 - | -LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const2.rs:54:36 - | -LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - | ^^^^^^^^ - -error: attempt to calculate the remainder with a divisor of zero - --> $DIR/issue-8460-const2.rs:56:36 - | -LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); - | ^^^^^^^^^ - -error: aborting due to 24 previous errors - diff --git a/src/test/ui/json-bom-plus-crlf-multifile.stderr b/src/test/ui/json-bom-plus-crlf-multifile.stderr index ab0feb3c451..026943669f8 100644 --- a/src/test/ui/json-bom-plus-crlf-multifile.stderr +++ b/src/test/ui/json-bom-plus-crlf-multifile.stderr @@ -1,10 +1,6 @@ -{"message":"mismatched types","code":{"code":"E0308","explanation":"This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. -For example: +Erroneous code example: ```compile_fail,E0308 let x: i32 = \"I am not a number!\"; @@ -15,15 +11,17 @@ let x: i32 = \"I am not a number!\"; // | // type `i32` assigned to variable `x` ``` -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types -"} -{"message":"mismatched types","code":{"code":"E0308","explanation":"This error occurs when the compiler was unable to infer the concrete type of a + +This error occurs when the compiler was unable to infer the concrete type of a variable. It can occur for several cases, the most common of which is a mismatch in the expected type that the compiler inferred for a variable's initializing expression, and the actual type explicitly assigned to the variable. +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. -For example: +Erroneous code example: ```compile_fail,E0308 let x: i32 = \"I am not a number!\"; @@ -34,15 +32,17 @@ let x: i32 = \"I am not a number!\"; // | // type `i32` assigned to variable `x` ``` -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types -"} -{"message":"mismatched types","code":{"code":"E0308","explanation":"This error occurs when the compiler was unable to infer the concrete type of a + +This error occurs when the compiler was unable to infer the concrete type of a variable. It can occur for several cases, the most common of which is a mismatch in the expected type that the compiler inferred for a variable's initializing expression, and the actual type explicitly assigned to the variable. +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. -For example: +Erroneous code example: ```compile_fail,E0308 let x: i32 = \"I am not a number!\"; @@ -53,15 +53,17 @@ let x: i32 = \"I am not a number!\"; // | // type `i32` assigned to variable `x` ``` -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types -"} -{"message":"mismatched types","code":{"code":"E0308","explanation":"This error occurs when the compiler was unable to infer the concrete type of a + +This error occurs when the compiler was unable to infer the concrete type of a variable. It can occur for several cases, the most common of which is a mismatch in the expected type that the compiler inferred for a variable's initializing expression, and the actual type explicitly assigned to the variable. +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. -For example: +Erroneous code example: ```compile_fail,E0308 let x: i32 = \"I am not a number!\"; @@ -72,6 +74,12 @@ let x: i32 = \"I am not a number!\"; // | // type `i32` assigned to variable `x` ``` + +This error occurs when the compiler was unable to infer the concrete type of a +variable. It can occur for several cases, the most common of which is a +mismatch in the expected type that the compiler inferred for a variable's +initializing expression, and the actual type explicitly assigned to the +variable. "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types "} {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors diff --git a/src/test/ui/json-bom-plus-crlf.stderr b/src/test/ui/json-bom-plus-crlf.stderr index 1dd898db3ad..735a46b8c87 100644 --- a/src/test/ui/json-bom-plus-crlf.stderr +++ b/src/test/ui/json-bom-plus-crlf.stderr @@ -1,10 +1,6 @@ -{"message":"mismatched types","code":{"code":"E0308","explanation":"This error occurs when the compiler was unable to infer the concrete type of a -variable. It can occur for several cases, the most common of which is a -mismatch in the expected type that the compiler inferred for a variable's -initializing expression, and the actual type explicitly assigned to the -variable. +{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. -For example: +Erroneous code example: ```compile_fail,E0308 let x: i32 = \"I am not a number!\"; @@ -15,15 +11,17 @@ let x: i32 = \"I am not a number!\"; // | // type `i32` assigned to variable `x` ``` -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types -"} -{"message":"mismatched types","code":{"code":"E0308","explanation":"This error occurs when the compiler was unable to infer the concrete type of a + +This error occurs when the compiler was unable to infer the concrete type of a variable. It can occur for several cases, the most common of which is a mismatch in the expected type that the compiler inferred for a variable's initializing expression, and the actual type explicitly assigned to the variable. +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. -For example: +Erroneous code example: ```compile_fail,E0308 let x: i32 = \"I am not a number!\"; @@ -34,15 +32,17 @@ let x: i32 = \"I am not a number!\"; // | // type `i32` assigned to variable `x` ``` -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types -"} -{"message":"mismatched types","code":{"code":"E0308","explanation":"This error occurs when the compiler was unable to infer the concrete type of a + +This error occurs when the compiler was unable to infer the concrete type of a variable. It can occur for several cases, the most common of which is a mismatch in the expected type that the compiler inferred for a variable's initializing expression, and the actual type explicitly assigned to the variable. +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. -For example: +Erroneous code example: ```compile_fail,E0308 let x: i32 = \"I am not a number!\"; @@ -53,15 +53,17 @@ let x: i32 = \"I am not a number!\"; // | // type `i32` assigned to variable `x` ``` -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types -"} -{"message":"mismatched types","code":{"code":"E0308","explanation":"This error occurs when the compiler was unable to infer the concrete type of a + +This error occurs when the compiler was unable to infer the concrete type of a variable. It can occur for several cases, the most common of which is a mismatch in the expected type that the compiler inferred for a variable's initializing expression, and the actual type explicitly assigned to the variable. +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types +"} +{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. -For example: +Erroneous code example: ```compile_fail,E0308 let x: i32 = \"I am not a number!\"; @@ -72,6 +74,12 @@ let x: i32 = \"I am not a number!\"; // | // type `i32` assigned to variable `x` ``` + +This error occurs when the compiler was unable to infer the concrete type of a +variable. It can occur for several cases, the most common of which is a +mismatch in the expected type that the compiler inferred for a variable's +initializing expression, and the actual type explicitly assigned to the +variable. "},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types "} {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors diff --git a/src/test/ui/json-short.stderr b/src/test/ui/json-short.stderr index 226343b1b8c..60c2582b11e 100644 --- a/src/test/ui/json-short.stderr +++ b/src/test/ui/json-short.stderr @@ -8,8 +8,10 @@ fn main() { } ``` -If you don't know the basics of Rust, you can go look to the Rust Book to get -started: https://doc.rust-lang.org/book/ +If you don't know the basics of Rust, you can look at the +[Rust Book][rust-book] to get started. + +[rust-book]: https://doc.rust-lang.org/book/ "},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":62,"byte_end":62,"line_start":1,"line_end":1,"column_start":63,"column_end":63,"is_primary":true,"text":[{"text":"// compile-flags: --json=diagnostic-short --error-format=json","highlight_start":63,"highlight_end":63}],"label":"consider adding a `main` function to `$DIR/json-short.rs`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-short.rs:1:63: error[E0601]: `main` function not found in crate `json_short` "} {"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.rs b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.rs index b07de3e341c..a46ce67d40d 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.rs +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.rs @@ -1,3 +1,4 @@ use extern::foo; //~ ERROR expected identifier, found keyword `extern` + //~| ERROR unresolved import `r#extern` fn main() {} diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr index 05802f2d367..edbb36452b6 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr @@ -9,5 +9,12 @@ help: you can escape reserved keywords to use them as identifiers LL | use r#extern::foo; | ^^^^^^^^ -error: aborting due to previous error +error[E0432]: unresolved import `r#extern` + --> $DIR/keyword-extern-as-identifier-use.rs:1:5 + | +LL | use extern::foo; + | ^^^^^^ maybe a missing crate `r#extern`? + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/label/label_break_value_illegal_uses.stderr b/src/test/ui/label/label_break_value_illegal_uses.stderr index fd8850dd8da..a2c75882be0 100644 --- a/src/test/ui/label/label_break_value_illegal_uses.stderr +++ b/src/test/ui/label/label_break_value_illegal_uses.stderr @@ -2,7 +2,10 @@ error: expected `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:6:12 | LL | unsafe 'b: {} - | ^^ expected `{` + | ^^---- + | | + | expected `{` + | help: try placing this code inside a block: `{ 'b: {} }` error: expected `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:10:13 diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr index 4e50064efb4..e60c461743c 100644 --- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr +++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr @@ -2,7 +2,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:19:5 | LL | struct Foo { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | foo: &'static T | ^^^^^^^^^^^^^^^ | @@ -16,7 +16,7 @@ error[E0309]: the parameter type `K` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19 | LL | trait X: Sized { - | - help: consider adding an explicit lifetime bound `K: 'a`... + | - help: consider adding an explicit lifetime bound...: `K: 'a` LL | fn foo<'a, L: X<&'a Nested>>(); | ^^^^^^^^^^^^^^^^ | @@ -45,7 +45,7 @@ error[E0309]: the parameter type `L` may not live long enough LL | fn baz<'a, L, M: X<&'a Nested>>() { | - ^^^^^^^^^^^^^^^^ | | - | help: consider adding an explicit lifetime bound `L: 'a`... + | help: consider adding an explicit lifetime bound...: `L: 'a` | note: ...so that the reference type `&'a Nested` does not outlive the data it points at --> $DIR/lifetime-doesnt-live-long-enough.rs:32:22 @@ -57,7 +57,7 @@ error[E0309]: the parameter type `K` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:41:33 | LL | impl Nested { - | - help: consider adding an explicit lifetime bound `K: 'a`... + | - help: consider adding an explicit lifetime bound...: `K: 'a` LL | fn generic_in_parent<'a, L: X<&'a Nested>>() { | ^^^^^^^^^^^^^^^^ | @@ -71,7 +71,7 @@ error[E0309]: the parameter type `M` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:44:36 | LL | fn generic_in_child<'a, 'b, L: X<&'a Nested>, M: 'b>() { - | ^^^^^^^^^^^^^^^^ -- help: consider adding an explicit lifetime bound `M: 'a`... + | ^^^^^^^^^^^^^^^^ -- help: consider adding an explicit lifetime bound...: `M: 'a +` | note: ...so that the reference type `&'a Nested` does not outlive the data it points at --> $DIR/lifetime-doesnt-live-long-enough.rs:44:36 diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr index fc9093bb2e4..4c788211576 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr @@ -7,7 +7,7 @@ LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { | lifetime `'a` defined here LL | LL | if x > y { x } else { y } - | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr index 3384c24da8f..11e7fa96d7e 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr @@ -7,7 +7,7 @@ LL | fn foo<'a>(&self, x: &'a i32) -> &i32 { | lifetime `'a` defined here LL | LL | x - | ^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` + | ^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr index 5ef29076e07..c41f08e691a 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr @@ -7,7 +7,7 @@ LL | fn foo<'a>(&self, x: &'a Foo) -> &'a Foo { | lifetime `'a` defined here LL | LL | if true { x } else { self } - | ^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` + | ^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1` error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr index 1c258ad98ba..1a19e81f235 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr @@ -6,7 +6,7 @@ LL | fn foo<'a>(&self, x: &i32) -> &i32 { | | | let's call the lifetime of this reference `'2` LL | x - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: aborting due to previous error diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr index ffe39fdd8c9..87b13dc1591 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr @@ -6,7 +6,7 @@ LL | fn foo<'a>(&self, x: &Foo) -> &Foo { | | | let's call the lifetime of this reference `'2` LL | if true { x } else { self } - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: aborting due to previous error diff --git a/src/test/ui/lint/deny-overflowing-literals.stderr b/src/test/ui/lint/deny-overflowing-literals.stderr index 7f59495023e..127dd4127c2 100644 --- a/src/test/ui/lint/deny-overflowing-literals.stderr +++ b/src/test/ui/lint/deny-overflowing-literals.stderr @@ -5,6 +5,7 @@ LL | let x: u8 = 256; | ^^^ | = note: `#[deny(overflowing_literals)]` on by default + = note: the literal `256` does not fit into the type `u8` whose range is `0..=255` error: range endpoint is out of range for `u8` --> $DIR/deny-overflowing-literals.rs:5:14 diff --git a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs new file mode 100644 index 00000000000..49d489d9168 --- /dev/null +++ b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.rs @@ -0,0 +1,10 @@ +// build-fail +// only-x86_64 + +fn main() { + Bug::V([0; !0]); //~ ERROR is too big for the current +} + +enum Bug { + V([u8; !0]), +} diff --git a/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr new file mode 100644 index 00000000000..d31ce9cfe0c --- /dev/null +++ b/src/test/ui/lint/issue-69485-var-size-diffs-too-large.stderr @@ -0,0 +1,8 @@ +error: the type `[u8; 18446744073709551615]` is too big for the current architecture + --> $DIR/issue-69485-var-size-diffs-too-large.rs:5:12 + | +LL | Bug::V([0; !0]); + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr new file mode 100644 index 00000000000..ce9b02b6d82 --- /dev/null +++ b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr @@ -0,0 +1,146 @@ +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:22:13 + | +LL | let _ = x << 42; + | ^^^^^^^ attempt to shift left with overflow + | +note: the lint level is defined here + --> $DIR/lint-exceeding-bitshifts.rs:9:9 + | +LL | #![deny(arithmetic_overflow, const_err)] + | ^^^^^^^^^^^^^^^^^^^ + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:27:15 + | +LL | let n = 1u8 << 8; + | ^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:29:15 + | +LL | let n = 1u16 << 16; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:31:15 + | +LL | let n = 1u32 << 32; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:33:15 + | +LL | let n = 1u64 << 64; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:35:15 + | +LL | let n = 1i8 << 8; + | ^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:37:15 + | +LL | let n = 1i16 << 16; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:39:15 + | +LL | let n = 1i32 << 32; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:41:15 + | +LL | let n = 1i64 << 64; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:44:15 + | +LL | let n = 1u8 >> 8; + | ^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:46:15 + | +LL | let n = 1u16 >> 16; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:48:15 + | +LL | let n = 1u32 >> 32; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:50:15 + | +LL | let n = 1u64 >> 64; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:52:15 + | +LL | let n = 1i8 >> 8; + | ^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:54:15 + | +LL | let n = 1i16 >> 16; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:56:15 + | +LL | let n = 1i32 >> 32; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:58:15 + | +LL | let n = 1i64 >> 64; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:62:15 + | +LL | let n = n << 8; + | ^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:64:15 + | +LL | let n = 1u8 << -8; + | ^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:69:15 + | +LL | let n = 1u8 << (4+4); + | ^^^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:71:15 + | +LL | let n = 1i64 >> [64][0]; + | ^^^^^^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:77:15 + | +LL | let n = 1_isize << BITS; + | ^^^^^^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:78:15 + | +LL | let n = 1_usize << BITS; + | ^^^^^^^^^^^^^^^ attempt to shift left with overflow + +error: aborting due to 23 previous errors + diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr new file mode 100644 index 00000000000..ce9b02b6d82 --- /dev/null +++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr @@ -0,0 +1,146 @@ +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:22:13 + | +LL | let _ = x << 42; + | ^^^^^^^ attempt to shift left with overflow + | +note: the lint level is defined here + --> $DIR/lint-exceeding-bitshifts.rs:9:9 + | +LL | #![deny(arithmetic_overflow, const_err)] + | ^^^^^^^^^^^^^^^^^^^ + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:27:15 + | +LL | let n = 1u8 << 8; + | ^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:29:15 + | +LL | let n = 1u16 << 16; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:31:15 + | +LL | let n = 1u32 << 32; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:33:15 + | +LL | let n = 1u64 << 64; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:35:15 + | +LL | let n = 1i8 << 8; + | ^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:37:15 + | +LL | let n = 1i16 << 16; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:39:15 + | +LL | let n = 1i32 << 32; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:41:15 + | +LL | let n = 1i64 << 64; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:44:15 + | +LL | let n = 1u8 >> 8; + | ^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:46:15 + | +LL | let n = 1u16 >> 16; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:48:15 + | +LL | let n = 1u32 >> 32; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:50:15 + | +LL | let n = 1u64 >> 64; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:52:15 + | +LL | let n = 1i8 >> 8; + | ^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:54:15 + | +LL | let n = 1i16 >> 16; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:56:15 + | +LL | let n = 1i32 >> 32; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:58:15 + | +LL | let n = 1i64 >> 64; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:62:15 + | +LL | let n = n << 8; + | ^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:64:15 + | +LL | let n = 1u8 << -8; + | ^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:69:15 + | +LL | let n = 1u8 << (4+4); + | ^^^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:71:15 + | +LL | let n = 1i64 >> [64][0]; + | ^^^^^^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:77:15 + | +LL | let n = 1_isize << BITS; + | ^^^^^^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:78:15 + | +LL | let n = 1_usize << BITS; + | ^^^^^^^^^^^^^^^ attempt to shift left with overflow + +error: aborting due to 23 previous errors + diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr new file mode 100644 index 00000000000..ce9b02b6d82 --- /dev/null +++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr @@ -0,0 +1,146 @@ +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:22:13 + | +LL | let _ = x << 42; + | ^^^^^^^ attempt to shift left with overflow + | +note: the lint level is defined here + --> $DIR/lint-exceeding-bitshifts.rs:9:9 + | +LL | #![deny(arithmetic_overflow, const_err)] + | ^^^^^^^^^^^^^^^^^^^ + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:27:15 + | +LL | let n = 1u8 << 8; + | ^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:29:15 + | +LL | let n = 1u16 << 16; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:31:15 + | +LL | let n = 1u32 << 32; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:33:15 + | +LL | let n = 1u64 << 64; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:35:15 + | +LL | let n = 1i8 << 8; + | ^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:37:15 + | +LL | let n = 1i16 << 16; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:39:15 + | +LL | let n = 1i32 << 32; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:41:15 + | +LL | let n = 1i64 << 64; + | ^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:44:15 + | +LL | let n = 1u8 >> 8; + | ^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:46:15 + | +LL | let n = 1u16 >> 16; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:48:15 + | +LL | let n = 1u32 >> 32; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:50:15 + | +LL | let n = 1u64 >> 64; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:52:15 + | +LL | let n = 1i8 >> 8; + | ^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:54:15 + | +LL | let n = 1i16 >> 16; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:56:15 + | +LL | let n = 1i32 >> 32; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:58:15 + | +LL | let n = 1i64 >> 64; + | ^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:62:15 + | +LL | let n = n << 8; + | ^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:64:15 + | +LL | let n = 1u8 << -8; + | ^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:69:15 + | +LL | let n = 1u8 << (4+4); + | ^^^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:71:15 + | +LL | let n = 1i64 >> [64][0]; + | ^^^^^^^^^^^^^^^ attempt to shift right with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:77:15 + | +LL | let n = 1_isize << BITS; + | ^^^^^^^^^^^^^^^ attempt to shift left with overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-exceeding-bitshifts.rs:78:15 + | +LL | let n = 1_usize << BITS; + | ^^^^^^^^^^^^^^^ attempt to shift left with overflow + +error: aborting due to 23 previous errors + diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.rs b/src/test/ui/lint/lint-exceeding-bitshifts.rs index 121e5b796bb..7deee5320a8 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.rs +++ b/src/test/ui/lint/lint-exceeding-bitshifts.rs @@ -1,50 +1,79 @@ +// revisions: noopt opt opt_with_overflow_checks +//[noopt]compile-flags: -C opt-level=0 +//[opt]compile-flags: -O +//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O + // build-fail -// compile-flags: -O -#![deny(exceeding_bitshifts, const_err)] +#![crate_type="lib"] +#![deny(arithmetic_overflow, const_err)] #![allow(unused_variables)] #![allow(dead_code)] -fn main() { +pub trait Foo { + const N: i32; +} + +impl Foo for Vec { + const N: i32 = T::N << 42; // FIXME this should warn +} + +pub fn foo(x: i32) { + let _ = x << 42; //~ ERROR: arithmetic operation will overflow +} + +pub fn main() { let n = 1u8 << 7; - let n = 1u8 << 8; //~ ERROR: attempt to shift left with overflow + let n = 1u8 << 8; //~ ERROR: arithmetic operation will overflow let n = 1u16 << 15; - let n = 1u16 << 16; //~ ERROR: attempt to shift left with overflow + let n = 1u16 << 16; //~ ERROR: arithmetic operation will overflow let n = 1u32 << 31; - let n = 1u32 << 32; //~ ERROR: attempt to shift left with overflow + let n = 1u32 << 32; //~ ERROR: arithmetic operation will overflow let n = 1u64 << 63; - let n = 1u64 << 64; //~ ERROR: attempt to shift left with overflow + let n = 1u64 << 64; //~ ERROR: arithmetic operation will overflow let n = 1i8 << 7; - let n = 1i8 << 8; //~ ERROR: attempt to shift left with overflow + let n = 1i8 << 8; //~ ERROR: arithmetic operation will overflow let n = 1i16 << 15; - let n = 1i16 << 16; //~ ERROR: attempt to shift left with overflow + let n = 1i16 << 16; //~ ERROR: arithmetic operation will overflow let n = 1i32 << 31; - let n = 1i32 << 32; //~ ERROR: attempt to shift left with overflow + let n = 1i32 << 32; //~ ERROR: arithmetic operation will overflow let n = 1i64 << 63; - let n = 1i64 << 64; //~ ERROR: attempt to shift left with overflow + let n = 1i64 << 64; //~ ERROR: arithmetic operation will overflow let n = 1u8 >> 7; - let n = 1u8 >> 8; //~ ERROR: attempt to shift right with overflow + let n = 1u8 >> 8; //~ ERROR: arithmetic operation will overflow let n = 1u16 >> 15; - let n = 1u16 >> 16; //~ ERROR: attempt to shift right with overflow + let n = 1u16 >> 16; //~ ERROR: arithmetic operation will overflow let n = 1u32 >> 31; - let n = 1u32 >> 32; //~ ERROR: attempt to shift right with overflow + let n = 1u32 >> 32; //~ ERROR: arithmetic operation will overflow let n = 1u64 >> 63; - let n = 1u64 >> 64; //~ ERROR: attempt to shift right with overflow + let n = 1u64 >> 64; //~ ERROR: arithmetic operation will overflow let n = 1i8 >> 7; - let n = 1i8 >> 8; //~ ERROR: attempt to shift right with overflow + let n = 1i8 >> 8; //~ ERROR: arithmetic operation will overflow let n = 1i16 >> 15; - let n = 1i16 >> 16; //~ ERROR: attempt to shift right with overflow + let n = 1i16 >> 16; //~ ERROR: arithmetic operation will overflow let n = 1i32 >> 31; - let n = 1i32 >> 32; //~ ERROR: attempt to shift right with overflow + let n = 1i32 >> 32; //~ ERROR: arithmetic operation will overflow let n = 1i64 >> 63; - let n = 1i64 >> 64; //~ ERROR: attempt to shift right with overflow + let n = 1i64 >> 64; //~ ERROR: arithmetic operation will overflow let n = 1u8; let n = n << 7; - let n = n << 8; //~ ERROR: attempt to shift left with overflow + let n = n << 8; //~ ERROR: arithmetic operation will overflow - let n = 1u8 << -8; //~ ERROR: attempt to shift left with overflow + let n = 1u8 << -8; //~ ERROR: arithmetic operation will overflow let n = 1i8<<(1isize+-1); + + let n = 1u8 << (4+3); + let n = 1u8 << (4+4); //~ ERROR: arithmetic operation will overflow + let n = 1i64 >> [63][0]; + let n = 1i64 >> [64][0]; //~ ERROR: arithmetic operation will overflow + + #[cfg(target_pointer_width = "32")] + const BITS: usize = 32; + #[cfg(target_pointer_width = "64")] + const BITS: usize = 64; + let n = 1_isize << BITS; //~ ERROR: arithmetic operation will overflow + let n = 1_usize << BITS; //~ ERROR: arithmetic operation will overflow } diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.stderr deleted file mode 100644 index 658577213b3..00000000000 --- a/src/test/ui/lint/lint-exceeding-bitshifts.stderr +++ /dev/null @@ -1,116 +0,0 @@ -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts.rs:10:15 - | -LL | let n = 1u8 << 8; - | ^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/lint-exceeding-bitshifts.rs:4:9 - | -LL | #![deny(exceeding_bitshifts, const_err)] - | ^^^^^^^^^^^^^^^^^^^ - -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts.rs:12:15 - | -LL | let n = 1u16 << 16; - | ^^^^^^^^^^ - -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts.rs:14:15 - | -LL | let n = 1u32 << 32; - | ^^^^^^^^^^ - -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts.rs:16:15 - | -LL | let n = 1u64 << 64; - | ^^^^^^^^^^ - -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts.rs:18:15 - | -LL | let n = 1i8 << 8; - | ^^^^^^^^ - -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts.rs:20:15 - | -LL | let n = 1i16 << 16; - | ^^^^^^^^^^ - -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts.rs:22:15 - | -LL | let n = 1i32 << 32; - | ^^^^^^^^^^ - -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts.rs:24:15 - | -LL | let n = 1i64 << 64; - | ^^^^^^^^^^ - -error: attempt to shift right with overflow - --> $DIR/lint-exceeding-bitshifts.rs:27:15 - | -LL | let n = 1u8 >> 8; - | ^^^^^^^^ - -error: attempt to shift right with overflow - --> $DIR/lint-exceeding-bitshifts.rs:29:15 - | -LL | let n = 1u16 >> 16; - | ^^^^^^^^^^ - -error: attempt to shift right with overflow - --> $DIR/lint-exceeding-bitshifts.rs:31:15 - | -LL | let n = 1u32 >> 32; - | ^^^^^^^^^^ - -error: attempt to shift right with overflow - --> $DIR/lint-exceeding-bitshifts.rs:33:15 - | -LL | let n = 1u64 >> 64; - | ^^^^^^^^^^ - -error: attempt to shift right with overflow - --> $DIR/lint-exceeding-bitshifts.rs:35:15 - | -LL | let n = 1i8 >> 8; - | ^^^^^^^^ - -error: attempt to shift right with overflow - --> $DIR/lint-exceeding-bitshifts.rs:37:15 - | -LL | let n = 1i16 >> 16; - | ^^^^^^^^^^ - -error: attempt to shift right with overflow - --> $DIR/lint-exceeding-bitshifts.rs:39:15 - | -LL | let n = 1i32 >> 32; - | ^^^^^^^^^^ - -error: attempt to shift right with overflow - --> $DIR/lint-exceeding-bitshifts.rs:41:15 - | -LL | let n = 1i64 >> 64; - | ^^^^^^^^^^ - -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts.rs:45:15 - | -LL | let n = n << 8; - | ^^^^^^ - -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts.rs:47:15 - | -LL | let n = 1u8 << -8; - | ^^^^^^^^^ - -error: aborting due to 18 previous errors - diff --git a/src/test/ui/lint/lint-exceeding-bitshifts2.rs b/src/test/ui/lint/lint-exceeding-bitshifts2.rs deleted file mode 100644 index 2a7cbc10f77..00000000000 --- a/src/test/ui/lint/lint-exceeding-bitshifts2.rs +++ /dev/null @@ -1,20 +0,0 @@ -// build-fail -// compile-flags: -O - -#![deny(exceeding_bitshifts, const_err)] -#![allow(unused_variables)] -#![allow(dead_code)] - -fn main() { - let n = 1u8 << (4+3); - let n = 1u8 << (4+4); //~ ERROR: attempt to shift left with overflow - let n = 1i64 >> [63][0]; - let n = 1i64 >> [64][0]; //~ ERROR: attempt to shift right with overflow - - #[cfg(target_pointer_width = "32")] - const BITS: usize = 32; - #[cfg(target_pointer_width = "64")] - const BITS: usize = 64; - let n = 1_isize << BITS; //~ ERROR: attempt to shift left with overflow - let n = 1_usize << BITS; //~ ERROR: attempt to shift left with overflow -} diff --git a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr b/src/test/ui/lint/lint-exceeding-bitshifts2.stderr deleted file mode 100644 index ac9f3b1e56b..00000000000 --- a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr +++ /dev/null @@ -1,32 +0,0 @@ -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts2.rs:10:15 - | -LL | let n = 1u8 << (4+4); - | ^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/lint-exceeding-bitshifts2.rs:4:9 - | -LL | #![deny(exceeding_bitshifts, const_err)] - | ^^^^^^^^^^^^^^^^^^^ - -error: attempt to shift right with overflow - --> $DIR/lint-exceeding-bitshifts2.rs:12:15 - | -LL | let n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ - -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts2.rs:18:15 - | -LL | let n = 1_isize << BITS; - | ^^^^^^^^^^^^^^^ - -error: attempt to shift left with overflow - --> $DIR/lint-exceeding-bitshifts2.rs:19:15 - | -LL | let n = 1_usize << BITS; - | ^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors - diff --git a/src/test/ui/lint/lint-missing-doc.rs b/src/test/ui/lint/lint-missing-doc.rs index a2466d28fb0..77f9a3770a3 100644 --- a/src/test/ui/lint/lint-missing-doc.rs +++ b/src/test/ui/lint/lint-missing-doc.rs @@ -60,7 +60,7 @@ pub trait D { } /// dox -pub trait E { +pub trait E: Sized { type AssociatedType; //~ ERROR: missing documentation for an associated type type AssociatedTypeDef = Self; //~ ERROR: missing documentation for an associated type diff --git a/src/test/ui/lint/lint-pre-expansion-extern-module.rs b/src/test/ui/lint/lint-pre-expansion-extern-module.rs new file mode 100644 index 00000000000..30e2ed8b7a6 --- /dev/null +++ b/src/test/ui/lint/lint-pre-expansion-extern-module.rs @@ -0,0 +1,7 @@ +// check-pass +// compile-flags: -W rust-2018-compatibility +// error-pattern: `try` is a keyword in the 2018 edition + +fn main() {} + +mod lint_pre_expansion_extern_module_aux; diff --git a/src/test/ui/lint/lint-pre-expansion-extern-module.stderr b/src/test/ui/lint/lint-pre-expansion-extern-module.stderr new file mode 100644 index 00000000000..c683a3fa670 --- /dev/null +++ b/src/test/ui/lint/lint-pre-expansion-extern-module.stderr @@ -0,0 +1,10 @@ +warning: `try` is a keyword in the 2018 edition + --> $DIR/lint_pre_expansion_extern_module_aux.rs:3:8 + | +LL | pub fn try() {} + | ^^^ help: you can use a raw identifier to stay compatible: `r#try` + | + = note: `-W keyword-idents` implied by `-W rust-2018-compatibility` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + diff --git a/src/test/ui/lint/lint-range-endpoint-overflow.stderr b/src/test/ui/lint/lint-range-endpoint-overflow.stderr index dff61e022eb..d2df7372741 100644 --- a/src/test/ui/lint/lint-range-endpoint-overflow.stderr +++ b/src/test/ui/lint/lint-range-endpoint-overflow.stderr @@ -15,18 +15,24 @@ error: literal out of range for `u8` | LL | let range_c = 0..=256; | ^^^ + | + = note: the literal `256` does not fit into the type `u8` whose range is `0..=255` error: literal out of range for `u8` --> $DIR/lint-range-endpoint-overflow.rs:7:19 | LL | let range_d = 256..5; | ^^^ + | + = note: the literal `256` does not fit into the type `u8` whose range is `0..=255` error: literal out of range for `u8` --> $DIR/lint-range-endpoint-overflow.rs:8:22 | LL | let range_e = 0..257; | ^^^ + | + = note: the literal `257` does not fit into the type `u8` whose range is `0..=255` error: range endpoint is out of range for `u8` --> $DIR/lint-range-endpoint-overflow.rs:9:20 diff --git a/src/test/ui/lint/lint-type-limits2.stderr b/src/test/ui/lint/lint-type-limits2.stderr index bf510823b56..1e3c88dfc46 100644 --- a/src/test/ui/lint/lint-type-limits2.stderr +++ b/src/test/ui/lint/lint-type-limits2.stderr @@ -17,6 +17,7 @@ note: the lint level is defined here | LL | #![warn(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ + = note: the literal `128` does not fit into the type `i8` whose range is `-128..=127` error: aborting due to previous error diff --git a/src/test/ui/lint/lint-type-limits3.stderr b/src/test/ui/lint/lint-type-limits3.stderr index 00441f99e60..150e9a2aa47 100644 --- a/src/test/ui/lint/lint-type-limits3.stderr +++ b/src/test/ui/lint/lint-type-limits3.stderr @@ -17,6 +17,7 @@ note: the lint level is defined here | LL | #![warn(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ + = note: the literal `200` does not fit into the type `i8` whose range is `-128..=127` error: aborting due to previous error diff --git a/src/test/ui/lint/lint-type-overflow.stderr b/src/test/ui/lint/lint-type-overflow.stderr index ec15313158d..7715c0d3a4d 100644 --- a/src/test/ui/lint/lint-type-overflow.stderr +++ b/src/test/ui/lint/lint-type-overflow.stderr @@ -9,108 +9,143 @@ note: the lint level is defined here | LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ + = note: the literal `256` does not fit into the type `u8` whose range is `0..=255` error: literal out of range for `u8` --> $DIR/lint-type-overflow.rs:13:14 | LL | let x1 = 256_u8; | ^^^^^^ + | + = note: the literal `256_u8` does not fit into the type `u8` whose range is `0..=255` error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:16:18 | LL | let x1: i8 = 128; | ^^^ + | + = note: the literal `128` does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:18:19 | LL | let x3: i8 = -129; | ^^^ + | + = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:19:19 | LL | let x3: i8 = -(129); | ^^^^^ + | + = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:20:20 | LL | let x3: i8 = -{129}; | ^^^ + | + = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:22:10 | LL | test(1000); | ^^^^ + | + = note: the literal `1000` does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:24:13 | LL | let x = 128_i8; | ^^^^^^ + | + = note: the literal `128_i8` does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i8` --> $DIR/lint-type-overflow.rs:28:14 | LL | let x = -129_i8; | ^^^^^^ + | + = note: the literal `129_i8` does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:32:18 | LL | let x: i32 = 2147483648; | ^^^^^^^^^^ + | + = note: the literal `2147483648` does not fit into the type `i32` whose range is `-2147483648..=2147483647` error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:33:13 | LL | let x = 2147483648_i32; | ^^^^^^^^^^^^^^ + | + = note: the literal `2147483648_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:36:19 | LL | let x: i32 = -2147483649; | ^^^^^^^^^^ + | + = note: the literal `2147483649` does not fit into the type `i32` whose range is `-2147483648..=2147483647` error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:37:14 | LL | let x = -2147483649_i32; | ^^^^^^^^^^^^^^ + | + = note: the literal `2147483649_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` error: literal out of range for `i32` --> $DIR/lint-type-overflow.rs:38:13 | LL | let x = 2147483648; | ^^^^^^^^^^ + | + = note: the literal `2147483648` does not fit into the type `i32` whose range is `-2147483648..=2147483647` error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:40:13 | LL | let x = 9223372036854775808_i64; | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the literal `9223372036854775808_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:42:13 | LL | let x = 18446744073709551615_i64; | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the literal `18446744073709551615_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:43:19 | LL | let x: i64 = -9223372036854775809; | ^^^^^^^^^^^^^^^^^^^ + | + = note: the literal `9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` error: literal out of range for `i64` --> $DIR/lint-type-overflow.rs:44:14 | LL | let x = -9223372036854775809_i64; | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the literal `9223372036854775809_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` error: aborting due to 18 previous errors diff --git a/src/test/ui/lint/lint-type-overflow2.stderr b/src/test/ui/lint/lint-type-overflow2.stderr index dfc691ab910..61e33b7a260 100644 --- a/src/test/ui/lint/lint-type-overflow2.stderr +++ b/src/test/ui/lint/lint-type-overflow2.stderr @@ -9,30 +9,39 @@ note: the lint level is defined here | LL | #![deny(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ + = note: the literal `128` does not fit into the type `i8` whose range is `-128..=127` error: literal out of range for `f32` --> $DIR/lint-type-overflow2.rs:9:14 | LL | let x = -3.40282357e+38_f32; | ^^^^^^^^^^^^^^^^^^ + | + = note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `std::f32::INFINITY` error: literal out of range for `f32` --> $DIR/lint-type-overflow2.rs:10:14 | LL | let x = 3.40282357e+38_f32; | ^^^^^^^^^^^^^^^^^^ + | + = note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `std::f32::INFINITY` error: literal out of range for `f64` --> $DIR/lint-type-overflow2.rs:11:14 | LL | let x = -1.7976931348623159e+308_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `std::f64::INFINITY` error: literal out of range for `f64` --> $DIR/lint-type-overflow2.rs:12:14 | LL | let x = 1.7976931348623159e+308_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `std::f64::INFINITY` error: aborting due to 5 previous errors diff --git a/src/test/ui/lint/lint-unused-mut-variables.rs b/src/test/ui/lint/lint-unused-mut-variables.rs index dd8dbda6d43..5c7ed9d5219 100644 --- a/src/test/ui/lint/lint-unused-mut-variables.rs +++ b/src/test/ui/lint/lint-unused-mut-variables.rs @@ -2,17 +2,17 @@ // Exercise the unused_mut attribute in some positive and negative cases -#![deny(unused_mut)] +#![warn(unused_mut)] #![feature(async_closure, raw_ref_op)] async fn baz_async( mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, ) {} fn baz( mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, #[allow(unused_mut)] (mut c, d): (i32, i32) ) {} @@ -21,13 +21,13 @@ struct RefStruct {} impl RefStruct { async fn baz_async( mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, ) {} fn baz( &self, mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, #[allow(unused_mut)] (mut c, d): (i32, i32) ) {} @@ -37,7 +37,7 @@ trait RefTrait { fn baz( &self, mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, #[allow(unused_mut)] (mut c, d): (i32, i32) ) {} @@ -46,7 +46,7 @@ impl RefTrait for () { fn baz( &self, mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, #[allow(unused_mut)] (mut c, d): (i32, i32) ) {} @@ -55,32 +55,32 @@ impl RefTrait for () { fn main() { let _ = async move | mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, | {}; let _ = | mut a: i32, - //~^ ERROR: variable does not need to be mutable + //~^ WARN: variable does not need to be mutable #[allow(unused_mut)] mut b: i32, #[allow(unused_mut)] (mut c, d): (i32, i32) | {}; // negative cases - let mut a = 3; //~ ERROR: variable does not need to be mutable + let mut a = 3; //~ WARN: variable does not need to be mutable - let mut a = 2; //~ ERROR: variable does not need to be mutable + let mut a = 2; //~ WARN: variable does not need to be mutable - let mut b = 3; //~ ERROR: variable does not need to be mutable + let mut b = 3; //~ WARN: variable does not need to be mutable - let mut a = vec![3]; //~ ERROR: variable does not need to be mutable + let mut a = vec![3]; //~ WARN: variable does not need to be mutable - let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable + let (mut a, b) = (1, 2); //~ WARN: variable does not need to be mutable - let mut a; //~ ERROR: variable does not need to be mutable + let mut a; //~ WARN: variable does not need to be mutable a = 3; - let mut b; //~ ERROR: variable does not need to be mutable + let mut b; //~ WARN: variable does not need to be mutable if true { b = 3; @@ -89,11 +89,11 @@ fn main() { } match 30 { - mut x => {} //~ ERROR: variable does not need to be mutable + mut x => {} //~ WARN: variable does not need to be mutable } match (30, 2) { - (mut x, 1) | //~ ERROR: variable does not need to be mutable + (mut x, 1) | //~ WARN: variable does not need to be mutable (mut x, 2) | (mut x, 3) => { @@ -101,20 +101,20 @@ fn main() { _ => {} } - let x = |mut y: isize| 10; //~ ERROR: variable does not need to be mutable + let x = |mut y: isize| 10; //~ WARN: variable does not need to be mutable - fn what(mut foo: isize) {} //~ ERROR: variable does not need to be mutable + fn what(mut foo: isize) {} //~ WARN: variable does not need to be mutable - let mut a = &mut 5; //~ ERROR: variable does not need to be mutable + let mut a = &mut 5; //~ WARN: variable does not need to be mutable *a = 4; let mut a = 5; - let mut b = (&mut a,); //~ ERROR: variable does not need to be mutable + let mut b = (&mut a,); //~ WARN: variable does not need to be mutable *b.0 = 4; - let mut x = &mut 1; //~ ERROR: variable does not need to be mutable + let mut x = &mut 1; //~ WARN: variable does not need to be mutable let mut f = || { *x += 1; @@ -122,11 +122,11 @@ fn main() { f(); fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] { - &mut arg[..] //~^ ERROR: variable does not need to be mutable + &mut arg[..] //~^ WARN: variable does not need to be mutable } - let mut v : &mut Vec<()> = &mut vec![]; //~ ERROR: variable does not need to be mutable + let mut v : &mut Vec<()> = &mut vec![]; //~ WARN: variable does not need to be mutable v.push(()); @@ -181,7 +181,7 @@ fn main() { let mut raw_address_of_mut = 1; // OK let mut_ptr = &raw mut raw_address_of_mut; - let mut raw_address_of_const = 1; //~ ERROR: variable does not need to be mutable + let mut raw_address_of_const = 1; //~ WARN: variable does not need to be mutable let const_ptr = &raw const raw_address_of_const; } diff --git a/src/test/ui/lint/lint-unused-mut-variables.stderr b/src/test/ui/lint/lint-unused-mut-variables.stderr index eda078da9a0..b56b3c7569f 100644 --- a/src/test/ui/lint/lint-unused-mut-variables.stderr +++ b/src/test/ui/lint/lint-unused-mut-variables.stderr @@ -1,4 +1,4 @@ -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:9:5 | LL | mut a: i32, @@ -9,18 +9,10 @@ LL | mut a: i32, note: the lint level is defined here --> $DIR/lint-unused-mut-variables.rs:5:9 | -LL | #![deny(unused_mut)] +LL | #![warn(unused_mut)] | ^^^^^^^^^^ -error: variable does not need to be mutable - --> $DIR/lint-unused-mut-variables.rs:14:5 - | -LL | mut a: i32, - | ----^ - | | - | help: remove this `mut` - -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:23:9 | LL | mut a: i32, @@ -28,7 +20,15 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable + --> $DIR/lint-unused-mut-variables.rs:14:5 + | +LL | mut a: i32, + | ----^ + | | + | help: remove this `mut` + +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:29:9 | LL | mut a: i32, @@ -36,7 +36,7 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:39:9 | LL | mut a: i32, @@ -44,7 +44,7 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:48:9 | LL | mut a: i32, @@ -52,7 +52,7 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:57:9 | LL | mut a: i32, @@ -60,7 +60,7 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:62:9 | LL | mut a: i32, @@ -68,7 +68,7 @@ LL | mut a: i32, | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:104:14 | LL | let x = |mut y: isize| 10; @@ -76,7 +76,7 @@ LL | let x = |mut y: isize| 10; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:69:9 | LL | let mut a = 3; @@ -84,7 +84,7 @@ LL | let mut a = 3; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:71:9 | LL | let mut a = 2; @@ -92,7 +92,7 @@ LL | let mut a = 2; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:73:9 | LL | let mut b = 3; @@ -100,7 +100,7 @@ LL | let mut b = 3; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:75:9 | LL | let mut a = vec![3]; @@ -108,7 +108,7 @@ LL | let mut a = vec![3]; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:77:10 | LL | let (mut a, b) = (1, 2); @@ -116,7 +116,7 @@ LL | let (mut a, b) = (1, 2); | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:79:9 | LL | let mut a; @@ -124,7 +124,7 @@ LL | let mut a; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:83:9 | LL | let mut b; @@ -132,7 +132,7 @@ LL | let mut b; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:92:9 | LL | mut x => {} @@ -140,7 +140,7 @@ LL | mut x => {} | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:96:8 | LL | (mut x, 1) | @@ -148,7 +148,7 @@ LL | (mut x, 1) | | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:109:9 | LL | let mut a = &mut 5; @@ -156,7 +156,7 @@ LL | let mut a = &mut 5; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:114:9 | LL | let mut b = (&mut a,); @@ -164,7 +164,7 @@ LL | let mut b = (&mut a,); | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:117:9 | LL | let mut x = &mut 1; @@ -172,7 +172,7 @@ LL | let mut x = &mut 1; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:129:9 | LL | let mut v : &mut Vec<()> = &mut vec![]; @@ -180,7 +180,7 @@ LL | let mut v : &mut Vec<()> = &mut vec![]; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:184:9 | LL | let mut raw_address_of_const = 1; @@ -188,7 +188,7 @@ LL | let mut raw_address_of_const = 1; | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:106:13 | LL | fn what(mut foo: isize) {} @@ -196,7 +196,7 @@ LL | fn what(mut foo: isize) {} | | | help: remove this `mut` -error: variable does not need to be mutable +warning: variable does not need to be mutable --> $DIR/lint-unused-mut-variables.rs:124:20 | LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] { @@ -218,5 +218,5 @@ note: the lint level is defined here LL | #[deny(unused_mut)] | ^^^^^^^^^^ -error: aborting due to 26 previous errors +error: aborting due to previous error diff --git a/src/test/ui/lint/lint_pre_expansion_extern_module_aux.rs b/src/test/ui/lint/lint_pre_expansion_extern_module_aux.rs new file mode 100644 index 00000000000..71dec40ea44 --- /dev/null +++ b/src/test/ui/lint/lint_pre_expansion_extern_module_aux.rs @@ -0,0 +1,3 @@ +// ignore-test: not a test + +pub fn try() {} diff --git a/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.rs b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.rs index f207b235735..08a5c6c2b63 100644 --- a/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.rs +++ b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.rs @@ -1,6 +1,6 @@ // aux-build:redundant-semi-proc-macro-def.rs -#![deny(redundant_semicolon)] +#![deny(redundant_semicolons)] extern crate redundant_semi_proc_macro; use redundant_semi_proc_macro::should_preserve_spans; diff --git a/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr index 8c5ee58dc12..a79fba9bf3f 100644 --- a/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr +++ b/src/test/ui/lint/redundant-semicolon/redundant-semi-proc-macro.stderr @@ -1,4 +1,4 @@ -TokenStream [Ident { ident: "fn", span: #0 bytes(197..199) }, Ident { ident: "span_preservation", span: #0 bytes(200..217) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(217..219) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "let", span: #0 bytes(227..230) }, Ident { ident: "tst", span: #0 bytes(231..234) }, Punct { ch: '=', spacing: Alone, span: #0 bytes(235..236) }, Literal { lit: Lit { kind: Integer, symbol: "123", suffix: None }, span: Span { lo: BytePos(237), hi: BytePos(240), ctxt: #0 } }, Punct { ch: ';', spacing: Joint, span: #0 bytes(240..241) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(241..242) }, Ident { ident: "match", span: #0 bytes(288..293) }, Ident { ident: "tst", span: #0 bytes(294..297) }, Group { delimiter: Brace, stream: TokenStream [Literal { lit: Lit { kind: Integer, symbol: "123", suffix: None }, span: Span { lo: BytePos(482), hi: BytePos(485), ctxt: #0 } }, Punct { ch: '=', spacing: Joint, span: #0 bytes(486..488) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(486..488) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(489..491) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(491..492) }, Ident { ident: "_", span: #0 bytes(501..502) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(503..505) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(503..505) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(506..508) }], span: #0 bytes(298..514) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(514..515) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(515..516) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(516..517) }], span: #0 bytes(221..561) }] +TokenStream [Ident { ident: "fn", span: #0 bytes(198..200) }, Ident { ident: "span_preservation", span: #0 bytes(201..218) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(218..220) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "let", span: #0 bytes(228..231) }, Ident { ident: "tst", span: #0 bytes(232..235) }, Punct { ch: '=', spacing: Alone, span: #0 bytes(236..237) }, Literal { lit: Lit { kind: Integer, symbol: "123", suffix: None }, span: Span { lo: BytePos(238), hi: BytePos(241), ctxt: #0 } }, Punct { ch: ';', spacing: Joint, span: #0 bytes(241..242) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(242..243) }, Ident { ident: "match", span: #0 bytes(289..294) }, Ident { ident: "tst", span: #0 bytes(295..298) }, Group { delimiter: Brace, stream: TokenStream [Literal { lit: Lit { kind: Integer, symbol: "123", suffix: None }, span: Span { lo: BytePos(483), hi: BytePos(486), ctxt: #0 } }, Punct { ch: '=', spacing: Joint, span: #0 bytes(487..489) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(487..489) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(490..492) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(492..493) }, Ident { ident: "_", span: #0 bytes(502..503) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(504..506) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(504..506) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(507..509) }], span: #0 bytes(299..515) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(515..516) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(516..517) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(517..518) }], span: #0 bytes(222..562) }] error: unnecessary trailing semicolon --> $DIR/redundant-semi-proc-macro.rs:9:19 | @@ -8,8 +8,8 @@ LL | let tst = 123;; note: the lint level is defined here --> $DIR/redundant-semi-proc-macro.rs:3:9 | -LL | #![deny(redundant_semicolon)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![deny(redundant_semicolons)] + | ^^^^^^^^^^^^^^^^^^^^ error: unnecessary trailing semicolons --> $DIR/redundant-semi-proc-macro.rs:16:7 diff --git a/src/test/ui/lint/suggestions.rs b/src/test/ui/lint/suggestions.rs index 29297d08dca..518b5f211e5 100644 --- a/src/test/ui/lint/suggestions.rs +++ b/src/test/ui/lint/suggestions.rs @@ -1,7 +1,6 @@ // ignore-tidy-tab #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896 -#![feature(no_debug)] #[no_mangle] const DISCOVERY: usize = 1; //~^ ERROR const items should never be `#[no_mangle]` @@ -39,9 +38,6 @@ struct Equinox { warp_factor: f32, } -#[no_debug] // should suggest removal of deprecated attribute -//~^ WARN deprecated -//~| HELP remove this attribute fn main() { while true { //~^ WARN denote infinite loops diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr index 4e218ed0f1a..0ef5d72609a 100644 --- a/src/test/ui/lint/suggestions.stderr +++ b/src/test/ui/lint/suggestions.stderr @@ -1,5 +1,5 @@ warning: denote infinite loops with `loop { ... }` - --> $DIR/suggestions.rs:46:5 + --> $DIR/suggestions.rs:42:5 | LL | while true { | ^^^^^^^^^^ help: use `loop` @@ -7,7 +7,7 @@ LL | while true { = note: `#[warn(while_true)]` on by default warning: unnecessary parentheses around assigned value - --> $DIR/suggestions.rs:49:31 + --> $DIR/suggestions.rs:45:31 | LL | let mut registry_no = (format!("NX-{}", 74205)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses @@ -18,16 +18,8 @@ note: the lint level is defined here LL | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896 | ^^^^^^^^^^^^^ -warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721 - --> $DIR/suggestions.rs:42:1 - | -LL | #[no_debug] // should suggest removal of deprecated attribute - | ^^^^^^^^^^^ help: remove this attribute - | - = note: `#[warn(deprecated)]` on by default - warning: variable does not need to be mutable - --> $DIR/suggestions.rs:49:13 + --> $DIR/suggestions.rs:45:13 | LL | let mut registry_no = (format!("NX-{}", 74205)); | ----^^^^^^^^^^^ @@ -41,7 +33,7 @@ LL | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issu | ^^^^^^^^^^ warning: variable does not need to be mutable - --> $DIR/suggestions.rs:55:13 + --> $DIR/suggestions.rs:51:13 | LL | let mut | _____________^ @@ -53,7 +45,7 @@ LL | || b = 1; | help: remove this `mut` error: const items should never be `#[no_mangle]` - --> $DIR/suggestions.rs:6:14 + --> $DIR/suggestions.rs:5:14 | LL | #[no_mangle] const DISCOVERY: usize = 1; | -----^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +55,7 @@ LL | #[no_mangle] const DISCOVERY: usize = 1; = note: `#[deny(no_mangle_const_items)]` on by default warning: functions generic over types or consts must be mangled - --> $DIR/suggestions.rs:12:1 + --> $DIR/suggestions.rs:11:1 | LL | #[no_mangle] | ------------ help: remove this attribute @@ -74,7 +66,7 @@ LL | pub fn defiant(_t: T) {} = note: `#[warn(no_mangle_generic_items)]` on by default warning: the `warp_factor:` in this pattern is redundant - --> $DIR/suggestions.rs:61:23 + --> $DIR/suggestions.rs:57:23 | LL | Equinox { warp_factor: warp_factor } => {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use shorthand field pattern: `warp_factor` @@ -82,7 +74,7 @@ LL | Equinox { warp_factor: warp_factor } => {} = note: `#[warn(non_shorthand_field_patterns)]` on by default error: const items should never be `#[no_mangle]` - --> $DIR/suggestions.rs:22:18 + --> $DIR/suggestions.rs:21:18 | LL | #[no_mangle] pub const DAUNTLESS: bool = true; | ---------^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +82,7 @@ LL | #[no_mangle] pub const DAUNTLESS: bool = true; | help: try a static value: `pub static` warning: functions generic over types or consts must be mangled - --> $DIR/suggestions.rs:25:18 + --> $DIR/suggestions.rs:24:18 | LL | #[no_mangle] pub fn val_jean() {} | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ @@ -98,7 +90,7 @@ LL | #[no_mangle] pub fn val_jean() {} | help: remove this attribute error: const items should never be `#[no_mangle]` - --> $DIR/suggestions.rs:30:18 + --> $DIR/suggestions.rs:29:18 | LL | #[no_mangle] pub(crate) const VETAR: bool = true; | ----------------^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +98,7 @@ LL | #[no_mangle] pub(crate) const VETAR: bool = true; | help: try a static value: `pub static` warning: functions generic over types or consts must be mangled - --> $DIR/suggestions.rs:33:18 + --> $DIR/suggestions.rs:32:18 | LL | #[no_mangle] pub(crate) fn crossfield() {} | ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/type-overflow.stderr b/src/test/ui/lint/type-overflow.stderr index 2432eb78b87..a7a788b877a 100644 --- a/src/test/ui/lint/type-overflow.stderr +++ b/src/test/ui/lint/type-overflow.stderr @@ -9,6 +9,7 @@ note: the lint level is defined here | LL | #![warn(overflowing_literals)] | ^^^^^^^^^^^^^^^^^^^^ + = note: the literal `255i8` does not fit into the type `i8` whose range is `-128..=127` warning: literal out of range for i8 --> $DIR/type-overflow.rs:10:16 @@ -16,7 +17,7 @@ warning: literal out of range for i8 LL | let fail = 0b1000_0001i8; | ^^^^^^^^^^^^^ help: consider using `u8` instead: `0b1000_0001u8` | - = note: the literal `0b1000_0001i8` (decimal `129`) does not fit into an `i8` and will become `-127i8` + = note: the literal `0b1000_0001i8` (decimal `129`) does not fit into the type `i8` and will become `-127i8` warning: literal out of range for i64 --> $DIR/type-overflow.rs:12:16 @@ -24,7 +25,7 @@ warning: literal out of range for i64 LL | let fail = 0x8000_0000_0000_0000i64; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x8000_0000_0000_0000u64` | - = note: the literal `0x8000_0000_0000_0000i64` (decimal `9223372036854775808`) does not fit into an `i64` and will become `-9223372036854775808i64` + = note: the literal `0x8000_0000_0000_0000i64` (decimal `9223372036854775808`) does not fit into the type `i64` and will become `-9223372036854775808i64` warning: literal out of range for u32 --> $DIR/type-overflow.rs:14:16 @@ -32,7 +33,7 @@ warning: literal out of range for u32 LL | let fail = 0x1_FFFF_FFFFu32; | ^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x1_FFFF_FFFFu64` | - = note: the literal `0x1_FFFF_FFFFu32` (decimal `8589934591`) does not fit into an `u32` and will become `4294967295u32` + = note: the literal `0x1_FFFF_FFFFu32` (decimal `8589934591`) does not fit into the type `u32` and will become `4294967295u32` warning: literal out of range for i128 --> $DIR/type-overflow.rs:16:22 @@ -40,7 +41,7 @@ warning: literal out of range for i128 LL | let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into an `i128` and will become `-170141183460469231731687303715884105728i128` + = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into the type `i128` and will become `-170141183460469231731687303715884105728i128` = help: consider using `u128` instead warning: literal out of range for i32 @@ -49,7 +50,7 @@ warning: literal out of range for i32 LL | let fail = 0x8FFF_FFFF_FFFF_FFFE; | ^^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `0x8FFF_FFFF_FFFF_FFFE` (decimal `10376293541461622782`) does not fit into an `i32` and will become `-2i32` + = note: the literal `0x8FFF_FFFF_FFFF_FFFE` (decimal `10376293541461622782`) does not fit into the type `i32` and will become `-2i32` = help: consider using `i128` instead warning: literal out of range for i8 @@ -58,5 +59,5 @@ warning: literal out of range for i8 LL | let fail = -0b1111_1111i8; | ^^^^^^^^^^^^^ help: consider using `i16` instead: `0b1111_1111i16` | - = note: the literal `0b1111_1111i8` (decimal `255`) does not fit into an `i8` and will become `-1i8` + = note: the literal `0b1111_1111i8` (decimal `255`) does not fit into the type `i8` and will become `-1i8` diff --git a/src/test/ui/lint/uninitialized-zeroed.stderr b/src/test/ui/lint/uninitialized-zeroed.stderr index 6d669184deb..bf0562713a4 100644 --- a/src/test/ui/lint/uninitialized-zeroed.stderr +++ b/src/test/ui/lint/uninitialized-zeroed.stderr @@ -1,4 +1,4 @@ -error: the type `&'static T` does not permit zero-initialization +error: the type `&T` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:29:32 | LL | let _val: &'static T = mem::zeroed(); @@ -14,7 +14,7 @@ LL | #![deny(invalid_value)] | ^^^^^^^^^^^^^ = note: references must be non-null -error: the type `&'static T` does not permit being left uninitialized +error: the type `&T` does not permit being left uninitialized --> $DIR/uninitialized-zeroed.rs:30:32 | LL | let _val: &'static T = mem::uninitialized(); @@ -25,7 +25,7 @@ LL | let _val: &'static T = mem::uninitialized(); | = note: references must be non-null -error: the type `Wrap<&'static T>` does not permit zero-initialization +error: the type `Wrap<&T>` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:32:38 | LL | let _val: Wrap<&'static T> = mem::zeroed(); @@ -40,7 +40,7 @@ note: references must be non-null (in this struct field) LL | struct Wrap { wrapped: T } | ^^^^^^^^^^ -error: the type `Wrap<&'static T>` does not permit being left uninitialized +error: the type `Wrap<&T>` does not permit being left uninitialized --> $DIR/uninitialized-zeroed.rs:33:38 | LL | let _val: Wrap<&'static T> = mem::uninitialized(); @@ -121,7 +121,7 @@ LL | let _val: Void = mem::uninitialized(); | = note: enums with no variants have no valid value -error: the type `&'static i32` does not permit zero-initialization +error: the type `&i32` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:49:34 | LL | let _val: &'static i32 = mem::zeroed(); @@ -132,7 +132,7 @@ LL | let _val: &'static i32 = mem::zeroed(); | = note: references must be non-null -error: the type `&'static i32` does not permit being left uninitialized +error: the type `&i32` does not permit being left uninitialized --> $DIR/uninitialized-zeroed.rs:50:34 | LL | let _val: &'static i32 = mem::uninitialized(); @@ -366,7 +366,7 @@ LL | let _val: NonBig = mem::uninitialized(); | = note: `NonBig` must be initialized inside its custom valid range -error: the type `&'static i32` does not permit zero-initialization +error: the type `&i32` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:84:34 | LL | let _val: &'static i32 = mem::transmute(0usize); @@ -377,7 +377,7 @@ LL | let _val: &'static i32 = mem::transmute(0usize); | = note: references must be non-null -error: the type `&'static [i32]` does not permit zero-initialization +error: the type `&[i32]` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:85:36 | LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize)); diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index 0dc0d247af5..7176f17bc3f 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -2,7 +2,7 @@ "message": "cannot find type `Iter` in this scope", "code": { "code": "E0412", - "explanation": "The type name used is not in scope. + "explanation": "A used type name is not in scope. Erroneous code examples: diff --git a/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr b/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr index 41ed545cf16..2f3d48bf039 100644 --- a/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr +++ b/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr @@ -13,66 +13,70 @@ LL | pong!(); error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error` --> $DIR/main.rs:10:20 | -LL | / macro_rules! pong { -LL | | () => { syntax error }; - | | ^^^^^ expected one of 8 possible tokens -LL | | } - | |_- in this expansion of `pong!` +LL | / macro_rules! pong { +LL | | () => { syntax error }; + | | ^^^^^ expected one of 8 possible tokens +LL | | } + | |__- in this expansion of `pong!` ... -LL | ping!(); - | -------- in this macro invocation +LL | ping!(); + | -------- in this macro invocation | - ::: <::ping::ping macros>:1:1 + ::: $DIR/auxiliary/ping.rs:5:1 | -LL | () => { pong ! () ; } - | --------------------- - | | | - | | in this macro invocation - | in this expansion of `ping!` +LL | / macro_rules! ping { +LL | | () => { +LL | | pong!(); + | | -------- in this macro invocation +LL | | } +LL | | } + | |_- in this expansion of `ping!` error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error` --> $DIR/main.rs:10:20 | -LL | / macro_rules! pong { -LL | | () => { syntax error }; - | | ^^^^^ expected one of 8 possible tokens -LL | | } - | |_- in this expansion of `pong!` (#5) +LL | / macro_rules! pong { +LL | | () => { syntax error }; + | | ^^^^^ expected one of 8 possible tokens +LL | | } + | |__- in this expansion of `pong!` (#5) ... -LL | deep!(); - | -------- in this macro invocation (#1) +LL | deep!(); + | -------- in this macro invocation (#1) | - ::: <::ping::deep macros>:1:1 + ::: $DIR/auxiliary/ping.rs:5:1 | -LL | () => { foo ! () ; } - | -------------------- - | | | - | | in this macro invocation (#2) - | in this expansion of `deep!` (#1) - | - ::: <::ping::foo macros>:1:1 - | -LL | () => { bar ! () ; } - | -------------------- - | | | - | | in this macro invocation (#3) - | in this expansion of `foo!` (#2) - | - ::: <::ping::bar macros>:1:1 - | -LL | () => { ping ! () ; } - | --------------------- - | | | - | | in this macro invocation (#4) - | in this expansion of `bar!` (#3) - | - ::: <::ping::ping macros>:1:1 - | -LL | () => { pong ! () ; } - | --------------------- - | | | - | | in this macro invocation (#5) - | in this expansion of `ping!` (#4) +LL | / macro_rules! ping { +LL | | () => { +LL | | pong!(); + | | -------- in this macro invocation (#5) +LL | | } +LL | | } + | |_- in this expansion of `ping!` (#4) +... +LL | / macro_rules! deep { +LL | | () => { +LL | | foo!(); + | | ------- in this macro invocation (#2) +LL | | } +LL | | } + | |__- in this expansion of `deep!` (#1) +... +LL | / macro_rules! foo { +LL | | () => { +LL | | bar!(); + | | ------- in this macro invocation (#3) +LL | | } +LL | | } + | |__- in this expansion of `foo!` (#2) +... +LL | / macro_rules! bar { +LL | | () => { +LL | | ping!(); + | | -------- in this macro invocation (#4) +LL | | } +LL | | } + | |__- in this expansion of `bar!` (#3) error: aborting due to 3 previous errors diff --git a/src/test/ui/macros/assert-trailing-junk.rs b/src/test/ui/macros/assert-trailing-junk.rs index 676ae05bf0f..cd7faf9bf8b 100644 --- a/src/test/ui/macros/assert-trailing-junk.rs +++ b/src/test/ui/macros/assert-trailing-junk.rs @@ -13,12 +13,12 @@ fn main() { //~^ ERROR no rules expected assert!(true "whatever" blah); - //~^ WARN unexpected string literal + //~^ ERROR unexpected string literal //~^^ ERROR no rules expected assert!(true;); - //~^ WARN macro requires an expression + //~^ ERROR macro requires an expression assert!(false || true "error message"); - //~^ WARN unexpected string literal + //~^ ERROR unexpected string literal } diff --git a/src/test/ui/macros/assert-trailing-junk.stderr b/src/test/ui/macros/assert-trailing-junk.stderr index 4d18a531a80..84a6768b3f4 100644 --- a/src/test/ui/macros/assert-trailing-junk.stderr +++ b/src/test/ui/macros/assert-trailing-junk.stderr @@ -18,15 +18,13 @@ LL | assert!(true, "whatever" blah); | | | help: missing comma here -warning: unexpected string literal +error: unexpected string literal --> $DIR/assert-trailing-junk.rs:15:18 | LL | assert!(true "whatever" blah); | -^^^^^^^^^^ | | | help: try adding a comma - | - = note: this is going to be an error in the future error: no rules expected the token `blah` --> $DIR/assert-trailing-junk.rs:15:29 @@ -36,25 +34,21 @@ LL | assert!(true "whatever" blah); | | | help: missing comma here -warning: macro requires an expression as an argument +error: macro requires an expression as an argument --> $DIR/assert-trailing-junk.rs:19:5 | LL | assert!(true;); | ^^^^^^^^^^^^-^^ | | | help: try removing semicolon - | - = note: this is going to be an error in the future -warning: unexpected string literal +error: unexpected string literal --> $DIR/assert-trailing-junk.rs:22:27 | LL | assert!(false || true "error message"); | -^^^^^^^^^^^^^^^ | | | help: try adding a comma - | - = note: this is going to be an error in the future -error: aborting due to 4 previous errors +error: aborting due to 7 previous errors diff --git a/src/test/ui/macros/issue-54441.rs b/src/test/ui/macros/issue-54441.rs index afdf76b7b58..b24d7e1f6be 100644 --- a/src/test/ui/macros/issue-54441.rs +++ b/src/test/ui/macros/issue-54441.rs @@ -1,6 +1,6 @@ macro_rules! m { () => { - let //~ ERROR expected + let //~ ERROR macro expansion ignores token `let` and any following }; } diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr index c94355f4716..752916e6655 100644 --- a/src/test/ui/macros/issue-54441.stderr +++ b/src/test/ui/macros/issue-54441.stderr @@ -1,13 +1,13 @@ -error: expected one of `async`, `const`, `crate`, `extern`, `fn`, `pub`, `static`, `type`, or `unsafe`, found keyword `let` +error: macro expansion ignores token `let` and any following --> $DIR/issue-54441.rs:3:9 | LL | let - | ^^^ expected one of 9 possible tokens + | ^^^ ... LL | m!(); - | ----- in this macro invocation + | ----- caused by the macro expansion here | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: the usage of `m!` is likely invalid in foreign item context error: aborting due to previous error diff --git a/src/test/ui/macros/issue-58490.rs b/src/test/ui/macros/issue-58490.rs new file mode 100644 index 00000000000..97e71c9a1ce --- /dev/null +++ b/src/test/ui/macros/issue-58490.rs @@ -0,0 +1,26 @@ +// Regression test for #58490 + +macro_rules! a { + ( @1 $i:item ) => { + a! { @2 $i } + }; + ( @2 $i:item ) => { + $i + }; +} +mod b { + a! { + @1 + #[macro_export] + macro_rules! b { () => () } + } + #[macro_export] + macro_rules! b { () => () } + //~^ ERROR: the name `b` is defined multiple times +} +mod c { + #[allow(unused_imports)] + use crate::b; +} + +fn main() {} diff --git a/src/test/ui/macros/issue-58490.stderr b/src/test/ui/macros/issue-58490.stderr new file mode 100644 index 00000000000..b1f0896f3b6 --- /dev/null +++ b/src/test/ui/macros/issue-58490.stderr @@ -0,0 +1,14 @@ +error[E0428]: the name `b` is defined multiple times + --> $DIR/issue-58490.rs:18:5 + | +LL | macro_rules! b { () => () } + | -------------- previous definition of the macro `b` here +... +LL | macro_rules! b { () => () } + | ^^^^^^^^^^^^^^ `b` redefined here + | + = note: `b` must be defined only once in the macro namespace of this module + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0428`. diff --git a/src/test/ui/macros/issue-68060.rs b/src/test/ui/macros/issue-68060.rs new file mode 100644 index 00000000000..85ebd66b66c --- /dev/null +++ b/src/test/ui/macros/issue-68060.rs @@ -0,0 +1,16 @@ +// build-fail + +#![feature(track_caller)] + +fn main() { + (0..) + .map( + #[target_feature(enable = "")] + //~^ ERROR: the feature named `` is not valid for this target + //~| ERROR: `#[target_feature(..)]` can only be applied to `unsafe` functions + #[track_caller] + //~^ ERROR: `#[track_caller]` requires Rust ABI + |_| (), + ) + .next(); +} diff --git a/src/test/ui/macros/issue-68060.stderr b/src/test/ui/macros/issue-68060.stderr new file mode 100644 index 00000000000..230867410d9 --- /dev/null +++ b/src/test/ui/macros/issue-68060.stderr @@ -0,0 +1,24 @@ +error: `#[target_feature(..)]` can only be applied to `unsafe` functions + --> $DIR/issue-68060.rs:8:13 + | +LL | #[target_feature(enable = "")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can only be applied to `unsafe` functions +... +LL | |_| (), + | ------ not an `unsafe` function + +error: the feature named `` is not valid for this target + --> $DIR/issue-68060.rs:8:30 + | +LL | #[target_feature(enable = "")] + | ^^^^^^^^^^^ `` is not valid for this target + +error[E0737]: `#[track_caller]` requires Rust ABI + --> $DIR/issue-68060.rs:11:13 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0737`. diff --git a/src/test/ui/macros/macro-comma-behavior.core.stderr b/src/test/ui/macros/macro-comma-behavior.core.stderr index dd0cac659fd..83a88ab3bd9 100644 --- a/src/test/ui/macros/macro-comma-behavior.core.stderr +++ b/src/test/ui/macros/macro-comma-behavior.core.stderr @@ -1,41 +1,41 @@ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:21:23 + --> $DIR/macro-comma-behavior.rs:20:23 | LL | assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:24:23 + --> $DIR/macro-comma-behavior.rs:23:23 | LL | assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:30:29 + --> $DIR/macro-comma-behavior.rs:29:29 | LL | debug_assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:33:29 + --> $DIR/macro-comma-behavior.rs:32:29 | LL | debug_assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:54:19 + --> $DIR/macro-comma-behavior.rs:53:19 | LL | format_args!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:72:21 + --> $DIR/macro-comma-behavior.rs:71:21 | LL | unimplemented!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:81:24 + --> $DIR/macro-comma-behavior.rs:80:24 | LL | write!(f, "{}",)?; | ^^ diff --git a/src/test/ui/macros/macro-comma-behavior.rs b/src/test/ui/macros/macro-comma-behavior.rs index 006319aa9f5..04714c65b5c 100644 --- a/src/test/ui/macros/macro-comma-behavior.rs +++ b/src/test/ui/macros/macro-comma-behavior.rs @@ -9,7 +9,6 @@ #[cfg(std)] use std::fmt; #[cfg(core)] use core::fmt; #[cfg(core)] #[lang = "eh_personality"] fn eh_personality() {} -#[cfg(core)] #[lang = "eh_unwind_resume"] fn eh_unwind_resume() {} #[cfg(core)] #[lang = "panic_impl"] fn panic_impl(panic: &core::panic::PanicInfo) -> ! { loop {} } // (see documentation of the similarly-named test in run-pass) diff --git a/src/test/ui/macros/macro-comma-behavior.std.stderr b/src/test/ui/macros/macro-comma-behavior.std.stderr index 4372d89fbf5..26445f2c5c5 100644 --- a/src/test/ui/macros/macro-comma-behavior.std.stderr +++ b/src/test/ui/macros/macro-comma-behavior.std.stderr @@ -1,59 +1,59 @@ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:21:23 + --> $DIR/macro-comma-behavior.rs:20:23 | LL | assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:24:23 + --> $DIR/macro-comma-behavior.rs:23:23 | LL | assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:30:29 + --> $DIR/macro-comma-behavior.rs:29:29 | LL | debug_assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:33:29 + --> $DIR/macro-comma-behavior.rs:32:29 | LL | debug_assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:38:18 + --> $DIR/macro-comma-behavior.rs:37:18 | LL | eprint!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:50:18 + --> $DIR/macro-comma-behavior.rs:49:18 | LL | format!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:54:19 + --> $DIR/macro-comma-behavior.rs:53:19 | LL | format_args!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:61:17 + --> $DIR/macro-comma-behavior.rs:60:17 | LL | print!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:72:21 + --> $DIR/macro-comma-behavior.rs:71:21 | LL | unimplemented!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:81:24 + --> $DIR/macro-comma-behavior.rs:80:24 | LL | write!(f, "{}",)?; | ^^ diff --git a/src/test/ui/macros/trace-macro.stderr b/src/test/ui/macros/trace-macro.stderr index 202a9235adb..6217decd8ef 100644 --- a/src/test/ui/macros/trace-macro.stderr +++ b/src/test/ui/macros/trace-macro.stderr @@ -5,5 +5,5 @@ LL | println!("Hello, World!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: expanding `println! { "Hello, World!" }` - = note: to `{ $crate :: io :: _print ($crate :: format_args_nl ! ("Hello, World!")) ; }` + = note: to `{ $crate :: io :: _print($crate :: format_args_nl ! ("Hello, World!")) ; }` diff --git a/src/test/ui/macros/unknown-builtin.rs b/src/test/ui/macros/unknown-builtin.rs index a96b99ae4ff..716a0005ba3 100644 --- a/src/test/ui/macros/unknown-builtin.rs +++ b/src/test/ui/macros/unknown-builtin.rs @@ -1,3 +1,8 @@ +// FIXME: missing sysroot spans (#53081) +// ignore-i586-unknown-linux-gnu +// ignore-i586-unknown-linux-musl +// ignore-i686-unknown-linux-musl + // error-pattern: cannot find a built-in macro with name `line` #![feature(rustc_attrs)] diff --git a/src/test/ui/macros/unknown-builtin.stderr b/src/test/ui/macros/unknown-builtin.stderr index f1e828a46d8..ed163750a6e 100644 --- a/src/test/ui/macros/unknown-builtin.stderr +++ b/src/test/ui/macros/unknown-builtin.stderr @@ -1,14 +1,18 @@ error: cannot find a built-in macro with name `unknown` - --> $DIR/unknown-builtin.rs:6:1 + --> $DIR/unknown-builtin.rs:11:1 | LL | macro_rules! unknown { () => () } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot find a built-in macro with name `line` - --> <::core::macros::builtin::line macros>:1:1 + --> $SRC_DIR/libcore/macros/mod.rs:LL:COL | -LL | () => { } ; - | ^^^^^^^^^^^ +LL | / macro_rules! line { +LL | | () => { +LL | | /* compiler built-in */ +LL | | }; +LL | | } + | |_____^ error: aborting due to 2 previous errors diff --git a/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs b/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs new file mode 100644 index 00000000000..24692f7cf52 --- /dev/null +++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs @@ -0,0 +1,10 @@ +fn main() {} + +struct CLI { + #[derive(parse())] + //~^ ERROR traits in `#[derive(...)]` don't accept arguments + //~| ERROR cannot find derive macro `parse` in this scope + //~| ERROR cannot find derive macro `parse` in this scope + path: (), + //~^ ERROR `derive` may only be applied to structs, enums and unions +} diff --git a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr new file mode 100644 index 00000000000..e8f96178d10 --- /dev/null +++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr @@ -0,0 +1,26 @@ +error: traits in `#[derive(...)]` don't accept arguments + --> $DIR/issue-69341-malformed-derive-inert.rs:4:19 + | +LL | #[derive(parse())] + | ^^ help: remove the arguments + +error: `derive` may only be applied to structs, enums and unions + --> $DIR/issue-69341-malformed-derive-inert.rs:8:5 + | +LL | path: (), + | ^^^^^^^^ + +error: cannot find derive macro `parse` in this scope + --> $DIR/issue-69341-malformed-derive-inert.rs:4:14 + | +LL | #[derive(parse())] + | ^^^^^ + +error: cannot find derive macro `parse` in this scope + --> $DIR/issue-69341-malformed-derive-inert.rs:4:14 + | +LL | #[derive(parse())] + | ^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/match/match-fn-call.stderr b/src/test/ui/match/match-fn-call.stderr index 2d7a0f16141..297aa4cd95d 100644 --- a/src/test/ui/match/match-fn-call.stderr +++ b/src/test/ui/match/match-fn-call.stderr @@ -1,4 +1,4 @@ -error[E0164]: expected tuple struct or tuple variant, found method `Path::new` +error[E0164]: expected tuple struct or tuple variant, found associated function `Path::new` --> $DIR/match-fn-call.rs:6:9 | LL | Path::new("foo") => println!("foo"), @@ -6,7 +6,7 @@ LL | Path::new("foo") => println!("foo"), | = help: for more information, visit https://doc.rust-lang.org/book/ch18-00-patterns.html -error[E0164]: expected tuple struct or tuple variant, found method `Path::new` +error[E0164]: expected tuple struct or tuple variant, found associated function `Path::new` --> $DIR/match-fn-call.rs:8:9 | LL | Path::new("bar") => println!("bar"), diff --git a/src/test/ui/match/match-ill-type2.stderr b/src/test/ui/match/match-ill-type2.stderr index 1cf61ebad43..5078f03d601 100644 --- a/src/test/ui/match/match-ill-type2.stderr +++ b/src/test/ui/match/match-ill-type2.stderr @@ -1,6 +1,9 @@ error[E0308]: mismatched types --> $DIR/match-ill-type2.rs:4:9 | +LL | match 1i32 { + | ---- this expression has type `i32` +LL | 1i32 => 1, LL | 2u32 => 1, | ^^^^ expected `i32`, found `u32` diff --git a/src/test/ui/match/match-tag-nullary.stderr b/src/test/ui/match/match-tag-nullary.stderr index 4b6260b2199..723c7fa92b1 100644 --- a/src/test/ui/match/match-tag-nullary.stderr +++ b/src/test/ui/match/match-tag-nullary.stderr @@ -1,8 +1,13 @@ error[E0308]: mismatched types --> $DIR/match-tag-nullary.rs:4:40 | +LL | enum B { B } + | - unit variant defined here +LL | LL | fn main() { let x: A = A::A; match x { B::B => { } } } - | ^^^^ expected enum `A`, found enum `B` + | - ^^^^ expected enum `A`, found enum `B` + | | + | this expression has type `A` error: aborting due to previous error diff --git a/src/test/ui/methods/assign-to-method.rs b/src/test/ui/methods/assign-to-method.rs new file mode 100644 index 00000000000..85beaee8df0 --- /dev/null +++ b/src/test/ui/methods/assign-to-method.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zsave-analysis +// Also regression test for #69409 + +struct Cat { + meows : usize, + how_hungry : isize, +} + +impl Cat { + pub fn speak(&self) { self.meows += 1; } +} + +fn cat(in_x : usize, in_y : isize) -> Cat { + Cat { + meows: in_x, + how_hungry: in_y + } +} + +fn main() { + let nyan : Cat = cat(52, 99); + nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method + nyan.speak += || println!("meow"); //~ ERROR attempted to take value of method +} diff --git a/src/test/ui/assign-to-method.stderr b/src/test/ui/methods/assign-to-method.stderr similarity index 65% rename from src/test/ui/assign-to-method.stderr rename to src/test/ui/methods/assign-to-method.stderr index feceadb6722..c0dd529b681 100644 --- a/src/test/ui/assign-to-method.stderr +++ b/src/test/ui/methods/assign-to-method.stderr @@ -1,16 +1,16 @@ error[E0615]: attempted to take value of method `speak` on type `Cat` - --> $DIR/assign-to-method.rs:20:8 + --> $DIR/assign-to-method.rs:22:10 | -LL | nyan.speak = || println!("meow"); - | ^^^^^ +LL | nyan.speak = || println!("meow"); + | ^^^^^ | = help: methods are immutable and cannot be assigned to error[E0615]: attempted to take value of method `speak` on type `Cat` - --> $DIR/assign-to-method.rs:21:8 + --> $DIR/assign-to-method.rs:23:10 | -LL | nyan.speak += || println!("meow"); - | ^^^^^ +LL | nyan.speak += || println!("meow"); + | ^^^^^ | = help: methods are immutable and cannot be assigned to diff --git a/src/test/ui/methods/method-call-err-msg.rs b/src/test/ui/methods/method-call-err-msg.rs index 5ff4b412667..9bfacc7babf 100644 --- a/src/test/ui/methods/method-call-err-msg.rs +++ b/src/test/ui/methods/method-call-err-msg.rs @@ -5,16 +5,18 @@ impl Foo { fn zero(self) -> Foo { self } fn one(self, _: isize) -> Foo { self } fn two(self, _: isize, _: isize) -> Foo { self } + fn three(self, _: T, _: T, _: T) -> Foo { self } } fn main() { let x = Foo; - x.zero(0) //~ ERROR this function takes 0 parameters but 1 parameter was supplied - .one() //~ ERROR this function takes 1 parameter but 0 parameters were supplied - .two(0); //~ ERROR this function takes 2 parameters but 1 parameter was supplied + x.zero(0) //~ ERROR this function takes 0 arguments but 1 argument was supplied + .one() //~ ERROR this function takes 1 argument but 0 arguments were supplied + .two(0); //~ ERROR this function takes 2 arguments but 1 argument was supplied let y = Foo; y.zero() .take() //~ ERROR no method named `take` found .one(0); + y.three::(); //~ ERROR this function takes 3 arguments but 0 arguments were supplied } diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index 7efdd91708a..4678642dd6d 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -1,47 +1,67 @@ -error[E0061]: this function takes 0 parameters but 1 parameter was supplied - --> $DIR/method-call-err-msg.rs:12:7 +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/method-call-err-msg.rs:13:7 | LL | fn zero(self) -> Foo { self } | -------------------- defined here ... LL | x.zero(0) - | ^^^^ expected 0 parameters + | ^^^^ - supplied 1 argument + | | + | expected 0 arguments -error[E0061]: this function takes 1 parameter but 0 parameters were supplied - --> $DIR/method-call-err-msg.rs:13:7 +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/method-call-err-msg.rs:14:7 | LL | fn one(self, _: isize) -> Foo { self } | ----------------------------- defined here ... LL | .one() - | ^^^ expected 1 parameter + | ^^^- supplied 0 arguments + | | + | expected 1 argument -error[E0061]: this function takes 2 parameters but 1 parameter was supplied - --> $DIR/method-call-err-msg.rs:14:7 +error[E0061]: this function takes 2 arguments but 1 argument was supplied + --> $DIR/method-call-err-msg.rs:15:7 | LL | fn two(self, _: isize, _: isize) -> Foo { self } | --------------------------------------- defined here ... LL | .two(0); - | ^^^ expected 2 parameters + | ^^^ - supplied 1 argument + | | + | expected 2 arguments error[E0599]: no method named `take` found for struct `Foo` in the current scope - --> $DIR/method-call-err-msg.rs:18:7 + --> $DIR/method-call-err-msg.rs:19:7 | LL | pub struct Foo; - | --------------- method `take` not found for this + | --------------- + | | + | method `take` not found for this + | doesn't satisfy `Foo: std::iter::Iterator` ... LL | .take() | ^^^^ method not found in `Foo` | = note: the method `take` exists but the following trait bounds were not satisfied: - `&mut Foo : std::iter::Iterator` + `Foo: std::iter::Iterator` + which is required by `&mut Foo: std::iter::Iterator` = help: items from traits can only be used if the trait is implemented and in scope - = note: the following traits define an item `take`, perhaps you need to implement one of them: - candidate #1: `std::io::Read` - candidate #2: `std::iter::Iterator` + = note: the following trait defines an item `take`, perhaps you need to implement it: + candidate #1: `std::iter::Iterator` + +error[E0061]: this function takes 3 arguments but 0 arguments were supplied + --> $DIR/method-call-err-msg.rs:21:7 + | +LL | fn three(self, _: T, _: T, _: T) -> Foo { self } + | ------------------------------------------ defined here +... +LL | y.three::(); + | ^^^^^--------- supplied 0 arguments + | | + | expected 3 arguments -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0061, E0599. For more information about an error, try `rustc --explain E0061`. diff --git a/src/test/ui/methods/method-on-ambiguous-numeric-type.stderr b/src/test/ui/methods/method-on-ambiguous-numeric-type.stderr index 10950834ad3..c6dde67cfeb 100644 --- a/src/test/ui/methods/method-on-ambiguous-numeric-type.stderr +++ b/src/test/ui/methods/method-on-ambiguous-numeric-type.stderr @@ -42,10 +42,13 @@ LL | ($ident:ident) => { let $ident: i32 = 42; } error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` --> $DIR/method-on-ambiguous-numeric-type.rs:30:9 | -LL | mac!(bar); - | ---------- you must specify a type for this binding, like `i32` LL | bar.pow(2); | ^^^ + | +help: you must specify a type for this binding, like `i32` + | +LL | ($ident:ident) => { let $ident: i32 = 42; } + | ^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/methods/method-path-in-pattern.rs b/src/test/ui/methods/method-path-in-pattern.rs index f94be1734b7..40645309552 100644 --- a/src/test/ui/methods/method-path-in-pattern.rs +++ b/src/test/ui/methods/method-path-in-pattern.rs @@ -13,20 +13,20 @@ impl MyTrait for Foo {} fn main() { match 0u32 { Foo::bar => {} - //~^ ERROR expected unit struct, unit variant or constant, found method `Foo::bar` + //~^ ERROR expected unit struct, unit variant or constant, found associated function } match 0u32 { ::bar => {} - //~^ ERROR expected unit struct, unit variant or constant, found method `Foo::bar` + //~^ ERROR expected unit struct, unit variant or constant, found associated function } match 0u32 { ::trait_bar => {} - //~^ ERROR expected unit struct, unit variant or constant, found method `Foo::trait_bar` + //~^ ERROR expected unit struct, unit variant or constant, found associated function } if let Foo::bar = 0u32 {} - //~^ ERROR expected unit struct, unit variant or constant, found method `Foo::bar` + //~^ ERROR expected unit struct, unit variant or constant, found associated function if let ::bar = 0u32 {} - //~^ ERROR expected unit struct, unit variant or constant, found method `Foo::bar` + //~^ ERROR expected unit struct, unit variant or constant, found associated function if let Foo::trait_bar = 0u32 {} - //~^ ERROR expected unit struct, unit variant or constant, found method `Foo::trait_bar` + //~^ ERROR expected unit struct, unit variant or constant, found associated function } diff --git a/src/test/ui/methods/method-path-in-pattern.stderr b/src/test/ui/methods/method-path-in-pattern.stderr index 6b0c5946ff8..1d1bdb6b052 100644 --- a/src/test/ui/methods/method-path-in-pattern.stderr +++ b/src/test/ui/methods/method-path-in-pattern.stderr @@ -1,34 +1,34 @@ -error[E0533]: expected unit struct, unit variant or constant, found method `Foo::bar` +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar` --> $DIR/method-path-in-pattern.rs:15:9 | LL | Foo::bar => {} | ^^^^^^^^ -error[E0533]: expected unit struct, unit variant or constant, found method `Foo::bar` +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar` --> $DIR/method-path-in-pattern.rs:19:9 | LL | ::bar => {} | ^^^^^^^^^^ -error[E0533]: expected unit struct, unit variant or constant, found method `Foo::trait_bar` +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::trait_bar` --> $DIR/method-path-in-pattern.rs:23:9 | LL | ::trait_bar => {} | ^^^^^^^^^^^^^^^^ -error[E0533]: expected unit struct, unit variant or constant, found method `Foo::bar` +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar` --> $DIR/method-path-in-pattern.rs:26:12 | LL | if let Foo::bar = 0u32 {} | ^^^^^^^^ -error[E0533]: expected unit struct, unit variant or constant, found method `Foo::bar` +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::bar` --> $DIR/method-path-in-pattern.rs:28:12 | LL | if let ::bar = 0u32 {} | ^^^^^^^^^^ -error[E0533]: expected unit struct, unit variant or constant, found method `Foo::trait_bar` +error[E0533]: expected unit struct, unit variant or constant, found associated function `Foo::trait_bar` --> $DIR/method-path-in-pattern.rs:30:12 | LL | if let Foo::trait_bar = 0u32 {} diff --git a/src/test/ui/methods/method-resolvable-path-in-pattern.rs b/src/test/ui/methods/method-resolvable-path-in-pattern.rs index c05160792d3..2973800a4d4 100644 --- a/src/test/ui/methods/method-resolvable-path-in-pattern.rs +++ b/src/test/ui/methods/method-resolvable-path-in-pattern.rs @@ -9,6 +9,6 @@ impl MyTrait for Foo {} fn main() { match 0u32 { ::trait_bar => {} - //~^ ERROR expected unit struct, unit variant or constant, found method `MyTrait::trait_bar` + //~^ ERROR expected unit struct, unit variant or constant, found associated function } } diff --git a/src/test/ui/methods/method-resolvable-path-in-pattern.stderr b/src/test/ui/methods/method-resolvable-path-in-pattern.stderr index 4b25b694e13..7c454a9a777 100644 --- a/src/test/ui/methods/method-resolvable-path-in-pattern.stderr +++ b/src/test/ui/methods/method-resolvable-path-in-pattern.stderr @@ -1,4 +1,4 @@ -error[E0532]: expected unit struct, unit variant or constant, found method `MyTrait::trait_bar` +error[E0532]: expected unit struct, unit variant or constant, found associated function `MyTrait::trait_bar` --> $DIR/method-resolvable-path-in-pattern.rs:11:9 | LL | ::trait_bar => {} diff --git a/src/test/ui/minus-string.stderr b/src/test/ui/minus-string.stderr index 9177082cf0b..3fbec7c89c9 100644 --- a/src/test/ui/minus-string.stderr +++ b/src/test/ui/minus-string.stderr @@ -3,8 +3,6 @@ error[E0600]: cannot apply unary operator `-` to type `std::string::String` | LL | fn main() { -"foo".to_string(); } | ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-` - | - = note: an implementation of `std::ops::Neg` might be missing for `std::string::String` error: aborting due to previous error diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.rs b/src/test/ui/mir-dataflow/indirect-mutation-offset.rs index 884c83b6616..caa307e269f 100644 --- a/src/test/ui/mir-dataflow/indirect-mutation-offset.rs +++ b/src/test/ui/mir-dataflow/indirect-mutation-offset.rs @@ -1,6 +1,11 @@ // compile-flags: -Zunleash-the-miri-inside-of-you -// ignore-test Temporarily ignored while this analysis is migrated to the new framework. +// This test demonstrates a shortcoming of the `MaybeMutBorrowedLocals` analysis. It does not +// handle code that takes a reference to one field of a struct, then use pointer arithmetic to +// transform it to another field of that same struct that may have interior mutability. For now, +// this is UB, but this may change in the future. See [rust-lang/unsafe-code-guidelines#134]. +// +// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134 #![feature(core_intrinsics, rustc_attrs, const_raw_ptr_deref)] diff --git a/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr b/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr index 0ae9a40c96a..8d3548ececd 100644 --- a/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr +++ b/src/test/ui/mir-dataflow/indirect-mutation-offset.stderr @@ -1,5 +1,5 @@ error: rustc_peek: bit not set - --> $DIR/indirect-mutation-offset.rs:34:14 + --> $DIR/indirect-mutation-offset.rs:41:14 | LL | unsafe { rustc_peek(x) }; | ^^^^^^^^^^^^^ diff --git a/src/test/ui/mir/issue-60390.rs b/src/test/ui/mir/issue-60390.rs new file mode 100644 index 00000000000..fd9d6b46dd4 --- /dev/null +++ b/src/test/ui/mir/issue-60390.rs @@ -0,0 +1,8 @@ +// check-pass +// compile-flags: --emit=mir,link +// Regression test for #60390, this ICE requires `--emit=mir` flag. + +fn main() { + enum Inner { Member(u32) }; + Inner::Member(0); +} diff --git a/src/test/ui/mir/mir_assign_eval_order.rs b/src/test/ui/mir/mir_assign_eval_order.rs index 1594421b0b1..799bf7f3a12 100644 --- a/src/test/ui/mir/mir_assign_eval_order.rs +++ b/src/test/ui/mir/mir_assign_eval_order.rs @@ -12,7 +12,7 @@ fn evaluate_reborrow_before_assign() { let y = &mut &2; let z = &3; // There's an implicit reborrow of `x` on the right-hand side of the - // assignement. Note that writing an explicit reborrow would not show this + // assignment. Note that writing an explicit reborrow would not show this // bug, as now there would be two reborrows on the right-hand side and at // least one of them would happen before the left-hand side is evaluated. *{ x = z; &mut *y } = x; diff --git a/src/test/ui/mismatched_types/E0409.stderr b/src/test/ui/mismatched_types/E0409.stderr index 2306fb35273..ef03b67b1b0 100644 --- a/src/test/ui/mismatched_types/E0409.stderr +++ b/src/test/ui/mismatched_types/E0409.stderr @@ -1,4 +1,4 @@ -error[E0409]: variable `y` is bound in inconsistent ways within the same match arm +error[E0409]: variable `y` is bound inconsistently across alternatives separated by `|` --> $DIR/E0409.rs:5:23 | LL | (0, ref y) | (y, 0) => {} @@ -12,7 +12,11 @@ error[E0308]: mismatched types LL | match x { | - this expression has type `({integer}, {integer})` LL | (0, ref y) | (y, 0) => {} - | ^ expected `&{integer}`, found integer + | ----- ^ expected `&{integer}`, found integer + | | + | first introduced with type `&{integer}` here + | + = note: in the same arm, a binding must have the same type in all alternatives error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/issue-36053-2.rs b/src/test/ui/mismatched_types/issue-36053-2.rs index 9035e3380b0..36211b4ce70 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.rs +++ b/src/test/ui/mismatched_types/issue-36053-2.rs @@ -1,3 +1,7 @@ +// FIXME: missing sysroot spans (#53081) +// ignore-i586-unknown-linux-gnu +// ignore-i586-unknown-linux-musl +// ignore-i686-unknown-linux-musl // Regression test for #36053. ICE was caused due to obligations // being added to a special, dedicated fulfillment cx during // a probe. diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index f8d677b99d6..f8c0470172d 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -1,15 +1,27 @@ -error[E0599]: no method named `count` found for struct `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope - --> $DIR/issue-36053-2.rs:7:55 +error[E0599]: no method named `count` found for struct `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>` in the current scope + --> $DIR/issue-36053-2.rs:11:55 | LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | ^^^^^ method not found in `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` + | -------------- ^^^^^ method not found in `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>` + | | + | doesn't satisfy `<_ as std::ops::FnOnce<(&&str,)>>::Output = bool` + | doesn't satisfy `_: std::ops::FnMut<(&&str,)>` + | + ::: $SRC_DIR/libcore/iter/adapters/mod.rs:LL:COL + | +LL | pub struct Filter { + | ----------------------- doesn't satisfy `_: std::iter::Iterator` | = note: the method `count` exists but the following trait bounds were not satisfied: - `&mut std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]> : std::iter::Iterator` - `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]> : std::iter::Iterator` + `<[closure@$DIR/issue-36053-2.rs:11:39: 11:53] as std::ops::FnOnce<(&&str,)>>::Output = bool` + which is required by `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` + `[closure@$DIR/issue-36053-2.rs:11:39: 11:53]: std::ops::FnMut<(&&str,)>` + which is required by `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` + `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` + which is required by `&mut std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:11:39: 11:53]>: std::iter::Iterator` error[E0631]: type mismatch in closure arguments - --> $DIR/issue-36053-2.rs:7:32 + --> $DIR/issue-36053-2.rs:11:32 | LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); | ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _` diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index 802a2fef6bd..c2bce305877 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -3,7 +3,8 @@ error[E0308]: mismatched types | LL | fn foo(&foo: Foo) { | ^^^^------ - | | + | | | + | | expected due to this | expected struct `Foo`, found reference | help: did you mean `foo`: `&Foo` | @@ -14,7 +15,7 @@ error[E0308]: mismatched types --> $DIR/issue-38371.rs:18:9 | LL | fn agh(&&bar: &u32) { - | ^^^^ + | ^^^^ ---- expected due to this | | | expected `u32`, found reference | help: you can probably remove the explicit borrow: `bar` @@ -26,7 +27,9 @@ error[E0308]: mismatched types --> $DIR/issue-38371.rs:21:8 | LL | fn bgh(&&bar: u32) { - | ^^^^^ expected `u32`, found reference + | ^^^^^ --- expected due to this + | | + | expected `u32`, found reference | = note: expected type `u32` found reference `&_` diff --git a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr index bbfb0005056..5ab191b9270 100644 --- a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr +++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -1,11 +1,14 @@ error[E0599]: no method named `unwrap` found for enum `std::result::Result<(), Foo>` in the current scope --> $DIR/method-help-unsatisfied-bound.rs:5:7 | +LL | struct Foo; + | ----------- doesn't satisfy `Foo: std::fmt::Debug` +... LL | a.unwrap(); | ^^^^^^ method not found in `std::result::Result<(), Foo>` | = note: the method `unwrap` exists but the following trait bounds were not satisfied: - `Foo : std::fmt::Debug` + `Foo: std::fmt::Debug` error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.rs b/src/test/ui/mismatched_types/overloaded-calls-bad.rs index 73e74a97f06..902a6ec81d6 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.rs +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.rs @@ -27,7 +27,7 @@ fn main() { }; let ans = s("what"); //~ ERROR mismatched types let ans = s(); - //~^ ERROR this function takes 1 parameter but 0 parameters were supplied + //~^ ERROR this function takes 1 argument but 0 arguments were supplied let ans = s("burma", "shave"); - //~^ ERROR this function takes 1 parameter but 2 parameters were supplied + //~^ ERROR this function takes 1 argument but 2 arguments were supplied } diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr index 5a5dd056261..706e25529bf 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr @@ -4,17 +4,21 @@ error[E0308]: mismatched types LL | let ans = s("what"); | ^^^^^^ expected `isize`, found `&str` -error[E0057]: this function takes 1 parameter but 0 parameters were supplied +error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/overloaded-calls-bad.rs:29:15 | LL | let ans = s(); - | ^^^ expected 1 parameter + | ^-- supplied 0 arguments + | | + | expected 1 argument -error[E0057]: this function takes 1 parameter but 2 parameters were supplied +error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/overloaded-calls-bad.rs:31:15 | LL | let ans = s("burma", "shave"); - | ^^^^^^^^^^^^^^^^^^^ expected 1 parameter + | ^ ------- ------- supplied 2 arguments + | | + | expected 1 argument error: aborting due to 3 previous errors diff --git a/src/test/ui/missing/missing-semicolon-warning.rs b/src/test/ui/missing/missing-semicolon-warning.rs deleted file mode 100644 index d962a52139e..00000000000 --- a/src/test/ui/missing/missing-semicolon-warning.rs +++ /dev/null @@ -1,12 +0,0 @@ -// build-pass (FIXME(62277): could be check-pass?) -#![allow(unused)] - -macro_rules! m { - ($($e1:expr),*; $($e2:expr),*) => { - $( let x = $e1 )*; //~ WARN expected `;` - $( println!("{}", $e2) )*; //~ WARN expected `;` - } -} - - -fn main() { m!(0, 0; 0, 0); } diff --git a/src/test/ui/missing/missing-semicolon-warning.stderr b/src/test/ui/missing/missing-semicolon-warning.stderr deleted file mode 100644 index ecaefd47de0..00000000000 --- a/src/test/ui/missing/missing-semicolon-warning.stderr +++ /dev/null @@ -1,24 +0,0 @@ -warning: expected `;`, found keyword `let` - --> $DIR/missing-semicolon-warning.rs:6:12 - | -LL | $( let x = $e1 )*; - | ^^^ -... -LL | fn main() { m!(0, 0; 0, 0); } - | --------------- in this macro invocation - | - = note: this was erroneously allowed and will become a hard error in a future release - = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: expected `;`, found `println` - --> $DIR/missing-semicolon-warning.rs:7:12 - | -LL | $( println!("{}", $e2) )*; - | ^^^^^^^ -... -LL | fn main() { m!(0, 0; 0, 0); } - | --------------- in this macro invocation - | - = note: this was erroneously allowed and will become a hard error in a future release - = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr index 98b74e5f5cb..91b3fe15c4b 100644 --- a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr +++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr @@ -1,10 +1,10 @@ error[E0583]: file not found for module `missing` - --> $DIR/foo.rs:4:5 + --> $DIR/foo.rs:4:1 | LL | mod missing; - | ^^^^^^^ + | ^^^^^^^^^^^^ | - = help: name the file either foo/missing.rs or foo/missing/mod.rs inside the directory "$DIR" + = help: to create the module `missing`, create file "$DIR/foo/missing.rs" error: aborting due to previous error diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr index 457e8fcccbf..f519de46c76 100644 --- a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr +++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr @@ -1,10 +1,10 @@ error[E0583]: file not found for module `missing` - --> $DIR/foo_inline.rs:4:9 + --> $DIR/foo_inline.rs:4:5 | LL | mod missing; - | ^^^^^^^ + | ^^^^^^^^^^^^ | - = help: name the file either missing.rs or missing/mod.rs inside the directory "$DIR/foo_inline/inline" + = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs" error: aborting due to previous error diff --git a/src/test/ui/mod/mod_file_disambig.rs b/src/test/ui/mod/mod_file_disambig.rs index ef203ef082b..7b182421d34 100644 --- a/src/test/ui/mod/mod_file_disambig.rs +++ b/src/test/ui/mod/mod_file_disambig.rs @@ -2,4 +2,5 @@ mod mod_file_disambig_aux; //~ ERROR file for module `mod_file_disambig_aux` fou fn main() { assert_eq!(mod_file_aux::bar(), 10); + //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` } diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr index 2b77d866fb3..490633a3fb0 100644 --- a/src/test/ui/mod/mod_file_disambig.stderr +++ b/src/test/ui/mod/mod_file_disambig.stderr @@ -1,11 +1,18 @@ error[E0584]: file for module `mod_file_disambig_aux` found at both mod_file_disambig_aux.rs and mod_file_disambig_aux/mod.rs - --> $DIR/mod_file_disambig.rs:1:5 + --> $DIR/mod_file_disambig.rs:1:1 | LL | mod mod_file_disambig_aux; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: delete or rename one of them to remove the ambiguity -error: aborting due to previous error +error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` + --> $DIR/mod_file_disambig.rs:4:16 + | +LL | assert_eq!(mod_file_aux::bar(), 10); + | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0584`. +Some errors have detailed explanations: E0433, E0584. +For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/mut/mut-pattern-mismatched.stderr b/src/test/ui/mut/mut-pattern-mismatched.stderr index ccc8ac1278c..cad1cef5155 100644 --- a/src/test/ui/mut/mut-pattern-mismatched.stderr +++ b/src/test/ui/mut/mut-pattern-mismatched.stderr @@ -3,6 +3,9 @@ error[E0308]: mismatched types | LL | let &_ | ^^ types differ in mutability +... +LL | = foo; + | --- this expression has type `&mut {integer}` | = note: expected mutable reference `&mut {integer}` found reference `&_` @@ -12,6 +15,9 @@ error[E0308]: mismatched types | LL | let &mut _ | ^^^^^^ types differ in mutability +... +LL | = bar; + | --- this expression has type `&{integer}` | = note: expected reference `&{integer}` found mutable reference `&mut _` diff --git a/src/test/ui/never_type/issue-2149.stderr b/src/test/ui/never_type/issue-2149.stderr index 9645244751d..3cdd6372ec1 100644 --- a/src/test/ui/never_type/issue-2149.stderr +++ b/src/test/ui/never_type/issue-2149.stderr @@ -13,8 +13,11 @@ LL | ["hi"].bind(|x| [x] ); | ^^^^ method not found in `[&str; 1]` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `bind`, perhaps you need to implement it: - candidate #1: `VecMonad` +note: `VecMonad` defines an item `bind`, perhaps you need to implement it + --> $DIR/issue-2149.rs:1:1 + | +LL | trait VecMonad { + | ^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/never_type/panic-uninitialized-zeroed.rs b/src/test/ui/never_type/panic-uninitialized-zeroed.rs deleted file mode 100644 index e0c30160b9e..00000000000 --- a/src/test/ui/never_type/panic-uninitialized-zeroed.rs +++ /dev/null @@ -1,102 +0,0 @@ -// run-pass -// ignore-wasm32-bare compiled with panic=abort by default -// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results -// in a runtime panic. - -#![feature(never_type)] -#![allow(deprecated, invalid_value)] - -use std::{mem, panic}; - -#[allow(dead_code)] -struct Foo { - x: u8, - y: !, -} - -enum Bar {} - -fn main() { - unsafe { - assert_eq!( - panic::catch_unwind(|| { - mem::uninitialized::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type !" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::zeroed::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type !" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::MaybeUninit::::uninit().assume_init() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type !" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::uninitialized::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Foo" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::zeroed::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Foo" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::MaybeUninit::::uninit().assume_init() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Foo" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::uninitialized::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Bar" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::zeroed::() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Bar" - })), - Some(true) - ); - - assert_eq!( - panic::catch_unwind(|| { - mem::MaybeUninit::::uninit().assume_init() - }).err().and_then(|a| a.downcast_ref::().map(|s| { - s == "Attempted to instantiate uninhabited type Bar" - })), - Some(true) - ); - } -} diff --git a/src/test/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.rs b/src/test/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.rs new file mode 100644 index 00000000000..96c8719468f --- /dev/null +++ b/src/test/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.rs @@ -0,0 +1,12 @@ +// Test that the 'static bound from the Copy impl is respected. Regression test for #29149. + +#[derive(Clone)] +struct Foo<'a>(&'a u32); +impl Copy for Foo<'static> {} + +fn main() { + let s = 2; + let a = (Foo(&s),); //~ ERROR `s` does not live long enough [E0597] + drop(a.0); + drop(a.0); +} diff --git a/src/test/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr b/src/test/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr new file mode 100644 index 00000000000..65be3b37e0e --- /dev/null +++ b/src/test/ui/nll/do-not-ignore-lifetime-bounds-in-copy-proj.stderr @@ -0,0 +1,14 @@ +error[E0597]: `s` does not live long enough + --> $DIR/do-not-ignore-lifetime-bounds-in-copy-proj.rs:9:18 + | +LL | let a = (Foo(&s),); + | ^^ borrowed value does not live long enough +LL | drop(a.0); + | --- copying this value requires that `s` is borrowed for `'static` +LL | drop(a.0); +LL | } + | - `s` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/dont-print-desugared.stderr b/src/test/ui/nll/dont-print-desugared.stderr index 45d7cbcdfbe..88773def8b7 100644 --- a/src/test/ui/nll/dont-print-desugared.stderr +++ b/src/test/ui/nll/dont-print-desugared.stderr @@ -2,10 +2,7 @@ error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/dont-print-desugared.rs:4:10 | LL | for &ref mut x in s {} - | -^^^^^^^^^ - | || - | |cannot borrow as mutable through `&` reference - | help: consider changing this to be a mutable reference: `&mut ref mut x` + | ^^^^^^^^^ cannot borrow as mutable through `&` reference error[E0597]: `y` does not live long enough --> $DIR/dont-print-desugared.rs:17:16 diff --git a/src/test/ui/nll/issue-54556-used-vs-unused-tails.rs b/src/test/ui/nll/issue-54556-used-vs-unused-tails.rs index 0d96767a05d..a111acca66f 100644 --- a/src/test/ui/nll/issue-54556-used-vs-unused-tails.rs +++ b/src/test/ui/nll/issue-54556-used-vs-unused-tails.rs @@ -1,4 +1,4 @@ -// Ths test case is exploring the space of how blocs with tail +// This test case is exploring the space of how blocks with tail // expressions and statements can be composed, trying to keep each // case on one line so that we can compare them via a vertical scan // with the human eye. diff --git a/src/test/ui/nll/issue-69114-static-mut-ty.rs b/src/test/ui/nll/issue-69114-static-mut-ty.rs new file mode 100644 index 00000000000..ce37da053e3 --- /dev/null +++ b/src/test/ui/nll/issue-69114-static-mut-ty.rs @@ -0,0 +1,30 @@ +// Check that borrowck ensures that `static mut` items have the expected type. + +static FOO: u8 = 42; +static mut BAR: &'static u8 = &FOO; +static mut BAR_ELIDED: &u8 = &FOO; + +fn main() { + unsafe { + println!("{} {}", BAR, BAR_ELIDED); + set_bar(); + set_bar_elided(); + println!("{} {}", BAR, BAR_ELIDED); + } +} + +fn set_bar() { + let n = 42; + unsafe { + BAR = &n; + //~^ ERROR does not live long enough + } +} + +fn set_bar_elided() { + let n = 42; + unsafe { + BAR_ELIDED = &n; + //~^ ERROR does not live long enough + } +} diff --git a/src/test/ui/nll/issue-69114-static-mut-ty.stderr b/src/test/ui/nll/issue-69114-static-mut-ty.stderr new file mode 100644 index 00000000000..5e55cb502ca --- /dev/null +++ b/src/test/ui/nll/issue-69114-static-mut-ty.stderr @@ -0,0 +1,27 @@ +error[E0597]: `n` does not live long enough + --> $DIR/issue-69114-static-mut-ty.rs:19:15 + | +LL | BAR = &n; + | ------^^ + | | | + | | borrowed value does not live long enough + | assignment requires that `n` is borrowed for `'static` +... +LL | } + | - `n` dropped here while still borrowed + +error[E0597]: `n` does not live long enough + --> $DIR/issue-69114-static-mut-ty.rs:27:22 + | +LL | BAR_ELIDED = &n; + | -------------^^ + | | | + | | borrowed value does not live long enough + | assignment requires that `n` is borrowed for `'static` +... +LL | } + | - `n` dropped here while still borrowed + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/issue-69114-static-ty.rs b/src/test/ui/nll/issue-69114-static-ty.rs new file mode 100644 index 00000000000..3318433a1c5 --- /dev/null +++ b/src/test/ui/nll/issue-69114-static-ty.rs @@ -0,0 +1,9 @@ +// Check that borrowck ensures that `static` items have the expected type. + +static FOO: &'static (dyn Fn(&'static u8) + Send + Sync) = &drop; + +fn main() { + let n = 42; + FOO(&n); + //~^ ERROR does not live long enough +} diff --git a/src/test/ui/nll/issue-69114-static-ty.stderr b/src/test/ui/nll/issue-69114-static-ty.stderr new file mode 100644 index 00000000000..0815e74b553 --- /dev/null +++ b/src/test/ui/nll/issue-69114-static-ty.stderr @@ -0,0 +1,15 @@ +error[E0597]: `n` does not live long enough + --> $DIR/issue-69114-static-ty.rs:7:9 + | +LL | FOO(&n); + | ----^^- + | | | + | | borrowed value does not live long enough + | argument requires that `n` is borrowed for `'static` +LL | +LL | } + | - `n` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/outlives-suggestion-simple.rs b/src/test/ui/nll/outlives-suggestion-simple.rs index 91a7a1d71e8..41e4d83aa92 100644 --- a/src/test/ui/nll/outlives-suggestion-simple.rs +++ b/src/test/ui/nll/outlives-suggestion-simple.rs @@ -70,7 +70,7 @@ pub struct Foo2<'a> { impl<'a> Foo2<'a> { // should not produce outlives suggestions to name 'self fn get_bar(&self) -> Bar2 { - Bar2::new(&self) //~ERROR borrowed data escapes outside of function + Bar2::new(&self) //~ERROR borrowed data escapes outside of associated function } } diff --git a/src/test/ui/nll/outlives-suggestion-simple.stderr b/src/test/ui/nll/outlives-suggestion-simple.stderr index db7f57ceccf..6300ea66511 100644 --- a/src/test/ui/nll/outlives-suggestion-simple.stderr +++ b/src/test/ui/nll/outlives-suggestion-simple.stderr @@ -93,16 +93,16 @@ LL | self.x | = help: consider adding the following bound: `'b: 'a` -error[E0521]: borrowed data escapes outside of function +error[E0521]: borrowed data escapes outside of associated function --> $DIR/outlives-suggestion-simple.rs:73:9 | LL | fn get_bar(&self) -> Bar2 { | ----- | | - | `self` declared here, outside of the function body - | `self` is a reference that is only valid in the function body + | `self` declared here, outside of the associated function body + | `self` is a reference that is only valid in the associated function body LL | Bar2::new(&self) - | ^^^^^^^^^^^^^^^^ `self` escapes the function body here + | ^^^^^^^^^^^^^^^^ `self` escapes the associated function body here error: aborting due to 9 previous errors diff --git a/src/test/ui/nll/user-annotations/type-annotation-with-hrtb.rs b/src/test/ui/nll/user-annotations/type-annotation-with-hrtb.rs new file mode 100644 index 00000000000..1f7c060386b --- /dev/null +++ b/src/test/ui/nll/user-annotations/type-annotation-with-hrtb.rs @@ -0,0 +1,33 @@ +// Regression test for issue #69490 + +// check-pass + +pub trait Trait { + const S: &'static str; +} + +impl Trait<()> for T +where + T: for<'a> Trait<&'a ()>, +{ + // Use of `T::S` here caused an ICE + const S: &'static str = T::S; +} + +// Some similar cases that didn't ICE: + +impl<'a, T> Trait<()> for (T,) +where + T: Trait<&'a ()>, +{ + const S: &'static str = T::S; +} + +impl Trait<()> for [T; 1] +where + T: Trait fn(&'a ())>, +{ + const S: &'static str = T::S; +} + +fn main() {} diff --git a/src/test/ui/no-landing-pads.rs b/src/test/ui/no-landing-pads.rs deleted file mode 100644 index d9d53210612..00000000000 --- a/src/test/ui/no-landing-pads.rs +++ /dev/null @@ -1,23 +0,0 @@ -// run-pass -// compile-flags: -Z no-landing-pads -C codegen-units=1 -// ignore-emscripten no threads support - -use std::thread; - -static mut HIT: bool = false; - -struct A; - -impl Drop for A { - fn drop(&mut self) { - unsafe { HIT = true; } - } -} - -fn main() { - thread::spawn(move|| -> () { - let _a = A; - panic!(); - }).join().unwrap_err(); - assert!(unsafe { !HIT }); -} diff --git a/src/test/ui/no_owned_box_lang_item.rs b/src/test/ui/no_owned_box_lang_item.rs index b76699c19ac..58e45ff73a5 100644 --- a/src/test/ui/no_owned_box_lang_item.rs +++ b/src/test/ui/no_owned_box_lang_item.rs @@ -12,5 +12,4 @@ fn main() { } #[lang = "eh_personality"] extern fn eh_personality() {} -#[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} #[lang = "panic_impl"] fn panic_impl(panic: &PanicInfo) -> ! { loop {} } diff --git a/src/test/ui/not-enough-arguments.rs b/src/test/ui/not-enough-arguments.rs index 309283ed7f4..631bb1dd274 100644 --- a/src/test/ui/not-enough-arguments.rs +++ b/src/test/ui/not-enough-arguments.rs @@ -8,5 +8,5 @@ fn foo(a: isize, b: isize, c: isize, d:isize) { fn main() { foo(1, 2, 3); - //~^ ERROR this function takes 4 parameters but 3 + //~^ ERROR this function takes 4 arguments but 3 } diff --git a/src/test/ui/not-enough-arguments.stderr b/src/test/ui/not-enough-arguments.stderr index c1ee43ea904..f2b57f71400 100644 --- a/src/test/ui/not-enough-arguments.stderr +++ b/src/test/ui/not-enough-arguments.stderr @@ -1,11 +1,13 @@ -error[E0061]: this function takes 4 parameters but 3 parameters were supplied +error[E0061]: this function takes 4 arguments but 3 arguments were supplied --> $DIR/not-enough-arguments.rs:10:3 | LL | fn foo(a: isize, b: isize, c: isize, d:isize) { | --------------------------------------------- defined here ... LL | foo(1, 2, 3); - | ^^^^^^^^^^^^ expected 4 parameters + | ^^^ - - - supplied 3 arguments + | | + | expected 4 arguments error: aborting due to previous error diff --git a/src/test/ui/object-pointer-types.stderr b/src/test/ui/object-pointer-types.stderr index 855894b4495..021aa8670f7 100644 --- a/src/test/ui/object-pointer-types.stderr +++ b/src/test/ui/object-pointer-types.stderr @@ -1,22 +1,20 @@ error[E0599]: no method named `owned` found for reference `&dyn Foo` in the current scope --> $DIR/object-pointer-types.rs:11:7 | +LL | fn owned(self: Box); + | --------- the method might not be found because of this arbitrary self type +... LL | x.owned(); | ^^^^^ method not found in `&dyn Foo` - | - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `owned`, perhaps you need to implement it: - candidate #1: `Foo` error[E0599]: no method named `owned` found for mutable reference `&mut dyn Foo` in the current scope --> $DIR/object-pointer-types.rs:17:7 | +LL | fn owned(self: Box); + | --------- the method might not be found because of this arbitrary self type +... LL | x.owned(); | ^^^^^ method not found in `&mut dyn Foo` - | - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `owned`, perhaps you need to implement it: - candidate #1: `Foo` error[E0599]: no method named `managed` found for struct `std::boxed::Box<(dyn Foo + 'static)>` in the current scope --> $DIR/object-pointer-types.rs:23:7 diff --git a/src/test/ui/on-unimplemented/feature-gate-on-unimplemented.stderr b/src/test/ui/on-unimplemented/feature-gate-on-unimplemented.stderr index 71baf92b2d4..a4b33963fb0 100644 --- a/src/test/ui/on-unimplemented/feature-gate-on-unimplemented.stderr +++ b/src/test/ui/on-unimplemented/feature-gate-on-unimplemented.stderr @@ -4,7 +4,6 @@ error[E0658]: this is an internal attribute that will never be stable LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/or-patterns/already-bound-name.stderr b/src/test/ui/or-patterns/already-bound-name.stderr index 9924b0d7f72..97933ca1229 100644 --- a/src/test/ui/or-patterns/already-bound-name.stderr +++ b/src/test/ui/or-patterns/already-bound-name.stderr @@ -86,12 +86,14 @@ error[E0308]: mismatched types --> $DIR/already-bound-name.rs:32:31 | LL | let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1)); - | ^ ------- this expression has type `E>` - | | - | expected integer, found enum `E` + | - ^ ------- this expression has type `E>` + | | | + | | expected integer, found enum `E` + | first introduced with type `{integer}` here | = note: expected type `{integer}` found type `E<{integer}>` + = note: a binding must have the same type in all alternatives error: aborting due to 15 previous errors diff --git a/src/test/ui/or-patterns/box-patterns.rs b/src/test/ui/or-patterns/box-patterns.rs new file mode 100644 index 00000000000..aafd4799383 --- /dev/null +++ b/src/test/ui/or-patterns/box-patterns.rs @@ -0,0 +1,37 @@ +// Test or-patterns with box-patterns + +// run-pass + +#![feature(or_patterns)] +#![feature(box_patterns)] + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +#[derive(Debug)] +enum Test { + Foo, + Bar, + Baz, + Qux, +} + +fn test(x: Option>) -> MatchArm { + match x { + Some(box Test::Foo | box Test::Bar) => MatchArm::Arm(0), + Some(box Test::Baz) => MatchArm::Arm(1), + Some(_) => MatchArm::Arm(2), + _ => MatchArm::Wild, + } +} + +fn main() { + assert_eq!(test(Some(Box::new(Test::Foo))), MatchArm::Arm(0)); + assert_eq!(test(Some(Box::new(Test::Bar))), MatchArm::Arm(0)); + assert_eq!(test(Some(Box::new(Test::Baz))), MatchArm::Arm(1)); + assert_eq!(test(Some(Box::new(Test::Qux))), MatchArm::Arm(2)); + assert_eq!(test(None), MatchArm::Wild); +} diff --git a/src/test/ui/or-patterns/inconsistent-modes.rs b/src/test/ui/or-patterns/inconsistent-modes.rs index 28b5f0c02fe..fd5cb01ab42 100644 --- a/src/test/ui/or-patterns/inconsistent-modes.rs +++ b/src/test/ui/or-patterns/inconsistent-modes.rs @@ -5,22 +5,22 @@ fn main() { // One level: let Ok(a) | Err(ref a): Result<&u8, u8> = Ok(&0); - //~^ ERROR variable `a` is bound in inconsistent ways + //~^ ERROR variable `a` is bound inconsistently let Ok(ref mut a) | Err(a): Result = Ok(0); - //~^ ERROR variable `a` is bound in inconsistent ways + //~^ ERROR variable `a` is bound inconsistently let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); - //~^ ERROR variable `a` is bound in inconsistent ways + //~^ ERROR variable `a` is bound inconsistently //~| ERROR mismatched types let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); - //~^ ERROR variable `a` is bound in inconsistent ways - //~| ERROR variable `b` is bound in inconsistent ways + //~^ ERROR variable `a` is bound inconsistently + //~| ERROR variable `b` is bound inconsistently //~| ERROR mismatched types // Two levels: let Ok(Ok(a) | Err(a)) | Err(ref a) = Err(0); - //~^ ERROR variable `a` is bound in inconsistent ways + //~^ ERROR variable `a` is bound inconsistently // Three levels: - let Ok([ Ok((Ok(ref a) | Err(a),)) | Err(a) ]) | Err(a) = Err(&1); - //~^ ERROR variable `a` is bound in inconsistent ways + let Ok([Ok((Ok(ref a) | Err(a),)) | Err(a)]) | Err(a) = Err(&1); + //~^ ERROR variable `a` is bound inconsistently } diff --git a/src/test/ui/or-patterns/inconsistent-modes.stderr b/src/test/ui/or-patterns/inconsistent-modes.stderr index c329f905960..c5dcef36e05 100644 --- a/src/test/ui/or-patterns/inconsistent-modes.stderr +++ b/src/test/ui/or-patterns/inconsistent-modes.stderr @@ -1,4 +1,4 @@ -error[E0409]: variable `a` is bound in inconsistent ways within the same match arm +error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|` --> $DIR/inconsistent-modes.rs:7:25 | LL | let Ok(a) | Err(ref a): Result<&u8, u8> = Ok(&0); @@ -6,7 +6,7 @@ LL | let Ok(a) | Err(ref a): Result<&u8, u8> = Ok(&0); | | | first binding -error[E0409]: variable `a` is bound in inconsistent ways within the same match arm +error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|` --> $DIR/inconsistent-modes.rs:9:29 | LL | let Ok(ref mut a) | Err(a): Result = Ok(0); @@ -14,25 +14,25 @@ LL | let Ok(ref mut a) | Err(a): Result = Ok(0); | | | first binding -error[E0409]: variable `a` is bound in inconsistent ways within the same match arm +error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|` --> $DIR/inconsistent-modes.rs:11:33 | LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); | - first binding ^ bound in different ways -error[E0409]: variable `a` is bound in inconsistent ways within the same match arm +error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|` --> $DIR/inconsistent-modes.rs:14:39 | LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); | - first binding ^ bound in different ways -error[E0409]: variable `b` is bound in inconsistent ways within the same match arm +error[E0409]: variable `b` is bound inconsistently across alternatives separated by `|` --> $DIR/inconsistent-modes.rs:14:46 | LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); | - first binding ^ bound in different ways -error[E0409]: variable `a` is bound in inconsistent ways within the same match arm +error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|` --> $DIR/inconsistent-modes.rs:20:38 | LL | let Ok(Ok(a) | Err(a)) | Err(ref a) = Err(0); @@ -40,35 +40,39 @@ LL | let Ok(Ok(a) | Err(a)) | Err(ref a) = Err(0); | | | first binding -error[E0409]: variable `a` is bound in inconsistent ways within the same match arm - --> $DIR/inconsistent-modes.rs:24:34 +error[E0409]: variable `a` is bound inconsistently across alternatives separated by `|` + --> $DIR/inconsistent-modes.rs:24:33 | -LL | let Ok([ Ok((Ok(ref a) | Err(a),)) | Err(a) ]) | Err(a) = Err(&1); - | - ^ bound in different ways - | | - | first binding +LL | let Ok([Ok((Ok(ref a) | Err(a),)) | Err(a)]) | Err(a) = Err(&1); + | - ^ bound in different ways + | | + | first binding error[E0308]: mismatched types --> $DIR/inconsistent-modes.rs:11:25 | LL | let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0); - | ^^^^^^^^^ -------------------- expected due to this - | | - | types differ in mutability + | ----- ^^^^^^^^^ -------------------- expected due to this + | | | + | | types differ in mutability + | first introduced with type `&&u8` here | = note: expected type `&&u8` found type `&mut &mut u8` + = note: a binding must have the same type in all alternatives error[E0308]: mismatched types --> $DIR/inconsistent-modes.rs:14:31 | LL | let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0)); - | ^^^^^^^^^ ----------- this expression has type `std::result::Result<({integer}, &{integer}), (_, _)>` - | | - | types differ in mutability + | ----- ^^^^^^^^^ ----------- this expression has type `std::result::Result<({integer}, &{integer}), (_, _)>` + | | | + | | types differ in mutability + | first introduced with type `&{integer}` here | = note: expected type `&{integer}` found type `&mut _` + = note: a binding must have the same type in all alternatives error: aborting due to 9 previous errors diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs new file mode 100644 index 00000000000..59533cefea6 --- /dev/null +++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs @@ -0,0 +1,9 @@ +#![feature(or_patterns)] + +fn main() { + let 0 | (1 | 2) = 0; //~ ERROR refutable pattern in local binding + match 0 { + //~^ ERROR non-exhaustive patterns + 0 | (1 | 2) => {} + } +} diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr new file mode 100644 index 00000000000..58286e87869 --- /dev/null +++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr @@ -0,0 +1,25 @@ +error[E0005]: refutable pattern in local binding: `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered + --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:4:9 + | +LL | let 0 | (1 | 2) = 0; + | ^^^^^^^^^^^ patterns `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +help: you might want to use `if let` to ignore the variant that isn't matched + | +LL | if let 0 | (1 | 2) = 0 { /* */ } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0004]: non-exhaustive patterns: `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered + --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:5:11 + | +LL | match 0 { + | ^ patterns `std::i32::MIN..=-1i32` and `3i32..=std::i32::MAX` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0004, E0005. +For more information about an error, try `rustc --explain E0004`. diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs new file mode 100644 index 00000000000..1de563dedbf --- /dev/null +++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs @@ -0,0 +1,9 @@ +// check-pass + +#![feature(or_patterns)] + +fn main() { + let 0 | (1 | _) = 0; + if let 0 | (1 | 2) = 0 {} + if let x @ 0 | x @ (1 | 2) = 0 {} +} diff --git a/src/test/ui/or-patterns/or-pattern-mismatch.rs b/src/test/ui/or-patterns/or-pattern-mismatch.rs deleted file mode 100644 index 973954bca5a..00000000000 --- a/src/test/ui/or-patterns/or-pattern-mismatch.rs +++ /dev/null @@ -1,4 +0,0 @@ -enum Blah { A(isize, isize, usize), B(isize, isize) } - -fn main() { match Blah::A(1, 1, 2) { Blah::A(_, x, y) | Blah::B(x, y) => { } } } -//~^ ERROR mismatched types diff --git a/src/test/ui/or-patterns/or-pattern-mismatch.stderr b/src/test/ui/or-patterns/or-pattern-mismatch.stderr deleted file mode 100644 index bc288e06250..00000000000 --- a/src/test/ui/or-patterns/or-pattern-mismatch.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/or-pattern-mismatch.rs:3:68 - | -LL | fn main() { match Blah::A(1, 1, 2) { Blah::A(_, x, y) | Blah::B(x, y) => { } } } - | ---------------- this expression has type `Blah` ^ expected `usize`, found `isize` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.rs b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.rs new file mode 100644 index 00000000000..5ec7dc6962c --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.rs @@ -0,0 +1,68 @@ +// Here we test type checking of bindings when combined with or-patterns. +// Specifically, we ensure that introducing bindings of different types result in type errors. + +#![feature(or_patterns)] + +fn main() { + enum Blah { + A(isize, isize, usize), + B(isize, isize), + } + + match Blah::A(1, 1, 2) { + Blah::A(_, x, y) | Blah::B(x, y) => {} //~ ERROR mismatched types + } + + match Some(Blah::A(1, 1, 2)) { + Some(Blah::A(_, x, y) | Blah::B(x, y)) => {} //~ ERROR mismatched types + } + + match (0u8, 1u16) { + (x, y) | (y, x) => {} //~ ERROR mismatched types + //~^ ERROR mismatched types + } + + match Some((0u8, Some((1u16, 2u32)))) { + Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} + //~^ ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + _ => {} + } + + if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) { + //~^ ERROR mismatched types + } + + if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) { + //~^ ERROR mismatched types + } + + if let (x, y) | (y, x) = (0u8, 1u16) { + //~^ ERROR mismatched types + //~| ERROR mismatched types + } + + if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) + //~^ ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types + = Some((0u8, Some((1u16, 2u32)))) + {} + + let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2); + //~^ ERROR mismatched types + + let (x, y) | (y, x) = (0u8, 1u16); + //~^ ERROR mismatched types + //~| ERROR mismatched types + + fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {} + //~^ ERROR mismatched types + + fn f2(((x, y) | (y, x)): (u8, u16)) {} + //~^ ERROR mismatched types + //~| ERROR mismatched types +} diff --git a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr new file mode 100644 index 00000000000..1dabb7c9754 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr @@ -0,0 +1,257 @@ +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:13:39 + | +LL | match Blah::A(1, 1, 2) { + | ---------------- this expression has type `main::Blah` +LL | Blah::A(_, x, y) | Blah::B(x, y) => {} + | - ^ expected `usize`, found `isize` + | | + | first introduced with type `usize` here + | + = note: in the same arm, a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:17:44 + | +LL | match Some(Blah::A(1, 1, 2)) { + | ---------------------- this expression has type `std::option::Option` +LL | Some(Blah::A(_, x, y) | Blah::B(x, y)) => {} + | - ^ expected `usize`, found `isize` + | | + | first introduced with type `usize` here + | + = note: in the same arm, a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:21:19 + | +LL | match (0u8, 1u16) { + | ----------- this expression has type `(u8, u16)` +LL | (x, y) | (y, x) => {} + | - ^ expected `u16`, found `u8` + | | + | first introduced with type `u16` here + | + = note: in the same arm, a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:21:22 + | +LL | match (0u8, 1u16) { + | ----------- this expression has type `(u8, u16)` +LL | (x, y) | (y, x) => {} + | - ^ expected `u8`, found `u16` + | | + | first introduced with type `u8` here + | + = note: in the same arm, a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:26:41 + | +LL | match Some((0u8, Some((1u16, 2u32)))) { + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` +LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} + | - ^ expected `u16`, found `u8` + | | + | first introduced with type `u16` here + | + = note: in the same arm, a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:26:50 + | +LL | match Some((0u8, Some((1u16, 2u32)))) { + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` +LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} + | - ^ expected `u8`, found `u16` + | | + | first introduced with type `u8` here + | + = note: in the same arm, a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:26:59 + | +LL | match Some((0u8, Some((1u16, 2u32)))) { + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` +LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} + | - ^ expected `u32`, found `u16` + | | + | first introduced with type `u32` here + | + = note: in the same arm, a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:26:62 + | +LL | match Some((0u8, Some((1u16, 2u32)))) { + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` +LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} + | - first introduced with type `u8` here ^ expected `u8`, found `u32` + | + = note: in the same arm, a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:34:42 + | +LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) { + | - ^ ---------------- this expression has type `main::Blah` + | | | + | | expected `usize`, found `isize` + | first introduced with type `usize` here + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:38:47 + | +LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) { + | - ^ ---------------------- this expression has type `std::option::Option` + | | | + | | expected `usize`, found `isize` + | first introduced with type `usize` here + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:42:22 + | +LL | if let (x, y) | (y, x) = (0u8, 1u16) { + | - ^ ----------- this expression has type `(u8, u16)` + | | | + | | expected `u16`, found `u8` + | first introduced with type `u16` here + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:42:25 + | +LL | if let (x, y) | (y, x) = (0u8, 1u16) { + | - ^ ----------- this expression has type `(u8, u16)` + | | | + | | expected `u8`, found `u16` + | first introduced with type `u8` here + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:47:44 + | +LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) + | - ^ expected `u16`, found `u8` + | | + | first introduced with type `u16` here +... +LL | = Some((0u8, Some((1u16, 2u32)))) + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:47:53 + | +LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) + | - ^ expected `u8`, found `u16` + | | + | first introduced with type `u8` here +... +LL | = Some((0u8, Some((1u16, 2u32)))) + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:47:62 + | +LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) + | - ^ expected `u32`, found `u16` + | | + | first introduced with type `u32` here +... +LL | = Some((0u8, Some((1u16, 2u32)))) + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:47:65 + | +LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) + | - first introduced with type `u8` here ^ expected `u8`, found `u32` +... +LL | = Some((0u8, Some((1u16, 2u32)))) + | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:55:39 + | +LL | let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2); + | - ^ ---------------- this expression has type `main::Blah` + | | | + | | expected `usize`, found `isize` + | first introduced with type `usize` here + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:58:19 + | +LL | let (x, y) | (y, x) = (0u8, 1u16); + | - ^ ----------- this expression has type `(u8, u16)` + | | | + | | expected `u16`, found `u8` + | first introduced with type `u16` here + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:58:22 + | +LL | let (x, y) | (y, x) = (0u8, 1u16); + | - ^ ----------- this expression has type `(u8, u16)` + | | | + | | expected `u8`, found `u16` + | first introduced with type `u8` here + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:62:42 + | +LL | fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {} + | - ^ ---- expected due to this + | | | + | | expected `usize`, found `isize` + | first introduced with type `usize` here + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:65:22 + | +LL | fn f2(((x, y) | (y, x)): (u8, u16)) {} + | - ^ --------- expected due to this + | | | + | | expected `u16`, found `u8` + | first introduced with type `u16` here + | + = note: a binding must have the same type in all alternatives + +error[E0308]: mismatched types + --> $DIR/or-patterns-binding-type-mismatch.rs:65:25 + | +LL | fn f2(((x, y) | (y, x)): (u8, u16)) {} + | - ^ --------- expected due to this + | | | + | | expected `u8`, found `u16` + | first introduced with type `u8` here + | + = note: a binding must have the same type in all alternatives + +error: aborting due to 22 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/or-patterns-default-binding-modes.rs b/src/test/ui/or-patterns/or-patterns-default-binding-modes.rs new file mode 100644 index 00000000000..3b6047c7be4 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-default-binding-modes.rs @@ -0,0 +1,132 @@ +// Test that or-patterns are pass-through with respect to default binding modes. + +// check-pass + +#![feature(or_patterns)] +#![allow(irrefutable_let_patterns)] + +fn main() { + // A regression test for a mistake we made at one point: + match &1 { + e @ &(1..=2) | e @ &(3..=4) => {} + _ => {} + } + + match &0 { + 0 | &1 => {} + _ => {} + } + + type R<'a> = &'a Result; + + let res: R<'_> = &Ok(0); + + match res { + // Alternatives propagate expected type / binding mode independently. + Ok(mut x) | &Err(mut x) => drop::(x), + } + match res { + &(Ok(x) | Err(x)) => drop::(x), + } + match res { + Ok(x) | Err(x) => drop::<&u8>(x), + } + if let Ok(mut x) | &Err(mut x) = res { + drop::(x); + } + if let &(Ok(x) | Err(x)) = res { + drop::(x); + } + let Ok(mut x) | &Err(mut x) = res; + drop::(x); + let &(Ok(x) | Err(x)) = res; + drop::(x); + let Ok(x) | Err(x) = res; + drop::<&u8>(x); + for Ok(mut x) | &Err(mut x) in std::iter::once(res) { + drop::(x); + } + for &(Ok(x) | Err(x)) in std::iter::once(res) { + drop::(x); + } + for Ok(x) | Err(x) in std::iter::once(res) { + drop::<&u8>(x); + } + fn f1((Ok(mut x) | &Err(mut x)): R<'_>) { + drop::(x); + } + fn f2(&(Ok(x) | Err(x)): R<'_>) { + drop::(x); + } + fn f3((Ok(x) | Err(x)): R<'_>) { + drop::<&u8>(x); + } + + // Wrap inside another type (a product for a simplity with irrefutable contexts). + #[derive(Copy, Clone)] + struct Wrap(T); + let wres = Wrap(res); + + match wres { + Wrap(Ok(mut x) | &Err(mut x)) => drop::(x), + } + match wres { + Wrap(&(Ok(x) | Err(x))) => drop::(x), + } + match wres { + Wrap(Ok(x) | Err(x)) => drop::<&u8>(x), + } + if let Wrap(Ok(mut x) | &Err(mut x)) = wres { + drop::(x); + } + if let Wrap(&(Ok(x) | Err(x))) = wres { + drop::(x); + } + if let Wrap(Ok(x) | Err(x)) = wres { + drop::<&u8>(x); + } + let Wrap(Ok(mut x) | &Err(mut x)) = wres; + drop::(x); + let Wrap(&(Ok(x) | Err(x))) = wres; + drop::(x); + let Wrap(Ok(x) | Err(x)) = wres; + drop::<&u8>(x); + for Wrap(Ok(mut x) | &Err(mut x)) in std::iter::once(wres) { + drop::(x); + } + for Wrap(&(Ok(x) | Err(x))) in std::iter::once(wres) { + drop::(x); + } + for Wrap(Ok(x) | Err(x)) in std::iter::once(wres) { + drop::<&u8>(x); + } + fn fw1(Wrap(Ok(mut x) | &Err(mut x)): Wrap>) { + drop::(x); + } + fn fw2(Wrap(&(Ok(x) | Err(x))): Wrap>) { + drop::(x); + } + fn fw3(Wrap(Ok(x) | Err(x)): Wrap>) { + drop::<&u8>(x); + } + + // Nest some more: + + enum Tri

{ + A(P), + B(P), + C(P), + } + + let tri = &Tri::A(&Ok(0)); + let Tri::A(Ok(mut x) | Err(mut x)) + | Tri::B(&Ok(mut x) | Err(mut x)) + | &Tri::C(Ok(mut x) | Err(mut x)) = tri; + drop::(x); + + match tri { + Tri::A(Ok(mut x) | Err(mut x)) + | Tri::B(&Ok(mut x) | Err(mut x)) + | &Tri::C(Ok(mut x) | Err(mut x)) => drop::(x), + } +} diff --git a/src/test/ui/or-patterns/slice-patterns.rs b/src/test/ui/or-patterns/slice-patterns.rs new file mode 100644 index 00000000000..05c907e8246 --- /dev/null +++ b/src/test/ui/or-patterns/slice-patterns.rs @@ -0,0 +1,53 @@ +// Test or-patterns with slice-patterns + +// run-pass + +#![feature(or_patterns)] + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +#[derive(Debug)] +enum Test { + Foo, + Bar, + Baz, + Qux, +} + +fn test(foo: &[Option]) -> MatchArm { + match foo { + [.., Some(Test::Qux | Test::Foo)] => MatchArm::Arm(0), + [Some(Test::Foo), .., Some(Test::Baz | Test::Bar)] => MatchArm::Arm(1), + [.., Some(Test::Bar | Test::Baz), _] => MatchArm::Arm(2), + _ => MatchArm::Wild, + } +} + +fn main() { + let foo = vec![ + Some(Test::Foo), + Some(Test::Bar), + Some(Test::Baz), + Some(Test::Qux), + ]; + + // path 1a + assert_eq!(test(&foo), MatchArm::Arm(0)); + // path 1b + assert_eq!(test(&[Some(Test::Bar), Some(Test::Foo)]), MatchArm::Arm(0)); + // path 2a + assert_eq!(test(&foo[..3]), MatchArm::Arm(1)); + // path 2b + assert_eq!(test(&[Some(Test::Foo), Some(Test::Foo), Some(Test::Bar)]), MatchArm::Arm(1)); + // path 3a + assert_eq!(test(&foo[1..3]), MatchArm::Arm(2)); + // path 3b + assert_eq!(test(&[Some(Test::Bar), Some(Test::Baz), Some(Test::Baz), Some(Test::Bar)]), + MatchArm::Arm(2)); + // path 4 + assert_eq!(test(&foo[4..]), MatchArm::Wild); +} diff --git a/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs b/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs index abe34a39caf..3e5cdad7ab9 100644 --- a/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs +++ b/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs @@ -11,5 +11,3 @@ use core::panic::PanicInfo; fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} -#[lang = "eh_unwind_resume"] -fn eh_unwind_resume() {} diff --git a/src/test/ui/panic-while-printing.rs b/src/test/ui/panic-while-printing.rs new file mode 100644 index 00000000000..7e9fa16b084 --- /dev/null +++ b/src/test/ui/panic-while-printing.rs @@ -0,0 +1,24 @@ +// run-pass +// ignore-emscripten no subprocess support + +#![feature(set_stdio)] + +use std::fmt; +use std::fmt::{Display, Formatter}; +use std::io::set_panic; + +pub struct A; + +impl Display for A { + fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result { + panic!(); + } +} + +fn main() { + set_panic(Some(Box::new(Vec::new()))); + assert!(std::panic::catch_unwind(|| { + eprintln!("{}", A); + }) + .is_err()); +} diff --git a/src/test/ui/parser/assoc-const-underscore-semantic-fail.rs b/src/test/ui/parser/assoc-const-underscore-semantic-fail.rs new file mode 100644 index 00000000000..d37ce06c555 --- /dev/null +++ b/src/test/ui/parser/assoc-const-underscore-semantic-fail.rs @@ -0,0 +1,17 @@ +// Semantically, an associated constant cannot use `_` as a name. + +fn main() {} + +const _: () = { + pub trait A { + const _: () = (); //~ ERROR `const` items in this context need a name + } + impl A for () { + const _: () = (); //~ ERROR `const` items in this context need a name + //~^ ERROR const `_` is not a member of trait `A` + } + struct B; + impl B { + const _: () = (); //~ ERROR `const` items in this context need a name + } +}; diff --git a/src/test/ui/parser/assoc-const-underscore-semantic-fail.stderr b/src/test/ui/parser/assoc-const-underscore-semantic-fail.stderr new file mode 100644 index 00000000000..538bf0ec100 --- /dev/null +++ b/src/test/ui/parser/assoc-const-underscore-semantic-fail.stderr @@ -0,0 +1,27 @@ +error: `const` items in this context need a name + --> $DIR/assoc-const-underscore-semantic-fail.rs:7:15 + | +LL | const _: () = (); + | ^ `_` is not a valid name for this `const` item + +error: `const` items in this context need a name + --> $DIR/assoc-const-underscore-semantic-fail.rs:10:15 + | +LL | const _: () = (); + | ^ `_` is not a valid name for this `const` item + +error: `const` items in this context need a name + --> $DIR/assoc-const-underscore-semantic-fail.rs:15:15 + | +LL | const _: () = (); + | ^ `_` is not a valid name for this `const` item + +error[E0438]: const `_` is not a member of trait `A` + --> $DIR/assoc-const-underscore-semantic-fail.rs:10:9 + | +LL | const _: () = (); + | ^^^^^^^^^^^^^^^^^ not a member of trait `A` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0438`. diff --git a/src/test/ui/parser/assoc-const-underscore-syntactic-pass.rs b/src/test/ui/parser/assoc-const-underscore-syntactic-pass.rs new file mode 100644 index 00000000000..60da408c811 --- /dev/null +++ b/src/test/ui/parser/assoc-const-underscore-syntactic-pass.rs @@ -0,0 +1,18 @@ +// All constant items (associated or otherwise) may syntactically use `_` as a name. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +const _: () = { + pub trait A { + const _: () = (); + } + impl A for () { + const _: () = (); + } + impl dyn A { + const _: () = (); + } +}; diff --git a/src/test/ui/parser/assoc-static-semantic-fail.rs b/src/test/ui/parser/assoc-static-semantic-fail.rs new file mode 100644 index 00000000000..215a2921315 --- /dev/null +++ b/src/test/ui/parser/assoc-static-semantic-fail.rs @@ -0,0 +1,51 @@ +// Semantically, we do not allow e.g., `static X: u8 = 0;` as an associated item. + +#![feature(specialization)] + +fn main() {} + +struct S; +impl S { + static IA: u8 = 0; + //~^ ERROR associated `static` items are not allowed + static IB: u8; + //~^ ERROR associated `static` items are not allowed + //~| ERROR associated constant in `impl` without body + default static IC: u8 = 0; + //~^ ERROR associated `static` items are not allowed + //~| ERROR a static item cannot be `default` + pub(crate) default static ID: u8; + //~^ ERROR associated `static` items are not allowed + //~| ERROR associated constant in `impl` without body + //~| ERROR a static item cannot be `default` +} + +trait T { + static TA: u8 = 0; + //~^ ERROR associated `static` items are not allowed + static TB: u8; + //~^ ERROR associated `static` items are not allowed + default static TC: u8 = 0; + //~^ ERROR associated `static` items are not allowed + //~| ERROR a static item cannot be `default` + pub(crate) default static TD: u8; + //~^ ERROR associated `static` items are not allowed + //~| ERROR unnecessary visibility qualifier + //~| ERROR a static item cannot be `default` +} + +impl T for S { + static TA: u8 = 0; + //~^ ERROR associated `static` items are not allowed + static TB: u8; + //~^ ERROR associated `static` items are not allowed + //~| ERROR associated constant in `impl` without body + default static TC: u8 = 0; + //~^ ERROR associated `static` items are not allowed + //~| ERROR a static item cannot be `default` + pub default static TD: u8; + //~^ ERROR associated `static` items are not allowed + //~| ERROR associated constant in `impl` without body + //~| ERROR unnecessary visibility qualifier + //~| ERROR a static item cannot be `default` +} diff --git a/src/test/ui/parser/assoc-static-semantic-fail.stderr b/src/test/ui/parser/assoc-static-semantic-fail.stderr new file mode 100644 index 00000000000..612297c9cd8 --- /dev/null +++ b/src/test/ui/parser/assoc-static-semantic-fail.stderr @@ -0,0 +1,167 @@ +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:9:5 + | +LL | static IA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:11:5 + | +LL | static IB: u8; + | ^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-semantic-fail.rs:14:5 + | +LL | default static IC: u8 = 0; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:14:5 + | +LL | default static IC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-semantic-fail.rs:17:16 + | +LL | pub(crate) default static ID: u8; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:17:5 + | +LL | pub(crate) default static ID: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:24:5 + | +LL | static TA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:26:5 + | +LL | static TB: u8; + | ^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-semantic-fail.rs:28:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:28:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-semantic-fail.rs:31:16 + | +LL | pub(crate) default static TD: u8; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:31:5 + | +LL | pub(crate) default static TD: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:38:5 + | +LL | static TA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:40:5 + | +LL | static TB: u8; + | ^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-semantic-fail.rs:43:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:43:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-semantic-fail.rs:46:9 + | +LL | pub default static TD: u8; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-semantic-fail.rs:46:5 + | +LL | pub default static TD: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated constant in `impl` without body + --> $DIR/assoc-static-semantic-fail.rs:11:5 + | +LL | static IB: u8; + | ^^^^^^^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + +error: associated constant in `impl` without body + --> $DIR/assoc-static-semantic-fail.rs:17:5 + | +LL | pub(crate) default static ID: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + +error[E0449]: unnecessary visibility qualifier + --> $DIR/assoc-static-semantic-fail.rs:31:5 + | +LL | pub(crate) default static TD: u8; + | ^^^^^^^^^^ + +error: associated constant in `impl` without body + --> $DIR/assoc-static-semantic-fail.rs:40:5 + | +LL | static TB: u8; + | ^^^^^^^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + +error: associated constant in `impl` without body + --> $DIR/assoc-static-semantic-fail.rs:46:5 + | +LL | pub default static TD: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + +error[E0449]: unnecessary visibility qualifier + --> $DIR/assoc-static-semantic-fail.rs:46:5 + | +LL | pub default static TD: u8; + | ^^^ `pub` not permitted here because it's implied + +error: aborting due to 24 previous errors + +For more information about this error, try `rustc --explain E0449`. diff --git a/src/test/ui/parser/assoc-static-syntactic-fail.rs b/src/test/ui/parser/assoc-static-syntactic-fail.rs new file mode 100644 index 00000000000..492f2ea16ef --- /dev/null +++ b/src/test/ui/parser/assoc-static-syntactic-fail.rs @@ -0,0 +1,33 @@ +// Syntactically, we do allow e.g., `static X: u8 = 0;` as an associated item. + +fn main() {} + +#[cfg(FALSE)] +impl S { + static IA: u8 = 0; //~ ERROR associated `static` items are not allowed + static IB: u8; //~ ERROR associated `static` items are not allowed + default static IC: u8 = 0; //~ ERROR associated `static` items are not allowed + //~^ ERROR a static item cannot be `default` + pub(crate) default static ID: u8; //~ ERROR associated `static` items are not allowed + //~^ ERROR a static item cannot be `default` +} + +#[cfg(FALSE)] +trait T { + static TA: u8 = 0; //~ ERROR associated `static` items are not allowed + static TB: u8; //~ ERROR associated `static` items are not allowed + default static TC: u8 = 0; //~ ERROR associated `static` items are not allowed + //~^ ERROR a static item cannot be `default` + pub(crate) default static TD: u8; //~ ERROR associated `static` items are not allowed + //~^ ERROR a static item cannot be `default` +} + +#[cfg(FALSE)] +impl T for S { + static TA: u8 = 0; //~ ERROR associated `static` items are not allowed + static TB: u8; //~ ERROR associated `static` items are not allowed + default static TC: u8 = 0; //~ ERROR associated `static` items are not allowed + //~^ ERROR a static item cannot be `default` + pub default static TD: u8; //~ ERROR associated `static` items are not allowed + //~^ ERROR a static item cannot be `default` +} diff --git a/src/test/ui/parser/assoc-static-syntactic-fail.stderr b/src/test/ui/parser/assoc-static-syntactic-fail.stderr new file mode 100644 index 00000000000..e9723614512 --- /dev/null +++ b/src/test/ui/parser/assoc-static-syntactic-fail.stderr @@ -0,0 +1,122 @@ +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:7:5 + | +LL | static IA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:8:5 + | +LL | static IB: u8; + | ^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-syntactic-fail.rs:9:5 + | +LL | default static IC: u8 = 0; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:9:5 + | +LL | default static IC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-syntactic-fail.rs:11:16 + | +LL | pub(crate) default static ID: u8; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:11:5 + | +LL | pub(crate) default static ID: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:17:5 + | +LL | static TA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:18:5 + | +LL | static TB: u8; + | ^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-syntactic-fail.rs:19:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:19:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-syntactic-fail.rs:21:16 + | +LL | pub(crate) default static TD: u8; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:21:5 + | +LL | pub(crate) default static TD: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:27:5 + | +LL | static TA: u8 = 0; + | ^^^^^^^^^^^^^^^^^^ + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:28:5 + | +LL | static TB: u8; + | ^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-syntactic-fail.rs:29:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:29:5 + | +LL | default static TC: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/assoc-static-syntactic-fail.rs:31:9 + | +LL | pub default static TD: u8; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/assoc-static-syntactic-fail.rs:31:5 + | +LL | pub default static TD: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 18 previous errors + diff --git a/src/test/ui/parser/attr-before-eof.stderr b/src/test/ui/parser/attr-before-eof.stderr index eb5daf84981..a2acb94372b 100644 --- a/src/test/ui/parser/attr-before-eof.stderr +++ b/src/test/ui/parser/attr-before-eof.stderr @@ -1,8 +1,8 @@ error: expected item after attributes - --> $DIR/attr-before-eof.rs:3:16 + --> $DIR/attr-before-eof.rs:3:1 | LL | #[derive(Debug)] - | ^ + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/attr-dangling-in-fn.stderr b/src/test/ui/parser/attr-dangling-in-fn.stderr index 71488d2e5c3..b1bb3ab3b17 100644 --- a/src/test/ui/parser/attr-dangling-in-fn.stderr +++ b/src/test/ui/parser/attr-dangling-in-fn.stderr @@ -1,8 +1,8 @@ error: expected statement after outer attribute - --> $DIR/attr-dangling-in-fn.rs:5:1 + --> $DIR/attr-dangling-in-fn.rs:4:3 | -LL | } - | ^ +LL | #[foo = "bar"] + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/attr-dangling-in-mod.stderr b/src/test/ui/parser/attr-dangling-in-mod.stderr index d896b61ce49..1c892eac08f 100644 --- a/src/test/ui/parser/attr-dangling-in-mod.stderr +++ b/src/test/ui/parser/attr-dangling-in-mod.stderr @@ -1,8 +1,8 @@ error: expected item after attributes - --> $DIR/attr-dangling-in-mod.rs:6:14 + --> $DIR/attr-dangling-in-mod.rs:6:1 | LL | #[foo = "bar"] - | ^ + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/attr-stmt-expr-attr-bad.rs b/src/test/ui/parser/attr-stmt-expr-attr-bad.rs index 118bff8144c..09f494bdc2f 100644 --- a/src/test/ui/parser/attr-stmt-expr-attr-bad.rs +++ b/src/test/ui/parser/attr-stmt-expr-attr-bad.rs @@ -38,42 +38,36 @@ fn main() {} //~^ ERROR an inner attribute is not permitted in this context #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = #[attr] if 0 {}; } -//~^ ERROR attributes are not yet allowed on `if` expressions #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } -//~^ ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context #[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; } //~^ ERROR expected one of #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } -//~^ ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } -//~^ ERROR attributes are not yet allowed on `if` expressions -//~| ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } -//~^ ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context -#[cfg(FALSE)] fn e() { let _ = #[attr] if let _ = 0 {}; } -//~^ ERROR attributes are not yet allowed on `if` expressions #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } -//~^ ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } //~^ ERROR expected one of #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } -//~^ ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } -//~^ ERROR attributes are not yet allowed on `if` expressions -//~| ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } -//~^ ERROR expected `{`, found `#` +//~^ ERROR outer attributes are not allowed on `if` #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } //~^ ERROR an inner attribute is not permitted in this context diff --git a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr index 4775b9b7bc0..6dfe7aad6ea 100644 --- a/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr +++ b/src/test/ui/parser/attr-stmt-expr-attr-bad.stderr @@ -136,23 +136,17 @@ LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; } | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. -error: attributes are not yet allowed on `if` expressions - --> $DIR/attr-stmt-expr-attr-bad.rs:41:32 - | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] if 0 {}; } - | ^^^^^^^ - -error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:43:37 +error: outer attributes are not allowed on `if` and `else` branches + --> $DIR/attr-stmt-expr-attr-bad.rs:41:37 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; } - | -- ^ --- help: try placing this code inside a block: `{ {}; }` + | -- ^^^^^^^ -- the attributes are attached to this branch | | | - | | expected `{` - | this `if` expression has a condition, but no block + | | help: remove the attributes + | the branch belongs to this `if` error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:45:38 + --> $DIR/attr-stmt-expr-attr-bad.rs:43:38 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } | ^^^^^^^^ @@ -160,75 +154,65 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; } = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:47:40 + --> $DIR/attr-stmt-expr-attr-bad.rs:45:40 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; } | ^ expected one of `.`, `;`, `?`, `else`, or an operator -error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:49:45 +error: outer attributes are not allowed on `if` and `else` branches + --> $DIR/attr-stmt-expr-attr-bad.rs:47:45 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; } - | ^ --- help: try placing this code inside a block: `{ {}; }` - | | - | expected `{` + | ---- ^^^^^^^ -- the attributes are attached to this branch + | | | + | | help: remove the attributes + | the branch belongs to this `else` error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:51:46 + --> $DIR/attr-stmt-expr-attr-bad.rs:49:46 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. -error: attributes are not yet allowed on `if` expressions - --> $DIR/attr-stmt-expr-attr-bad.rs:53:45 +error: outer attributes are not allowed on `if` and `else` branches + --> $DIR/attr-stmt-expr-attr-bad.rs:51:45 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } - | ^^^^^^^ + | ---- ^^^^^^^ ------- the attributes are attached to this branch + | | | + | | help: remove the attributes + | the branch belongs to this `else` -error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:53:45 - | -LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; } - | ^ -------- help: try placing this code inside a block: `{ if 0 {}; }` - | | - | expected `{` - -error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:56:50 +error: outer attributes are not allowed on `if` and `else` branches + --> $DIR/attr-stmt-expr-attr-bad.rs:53:50 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; } - | -- ^ --- help: try placing this code inside a block: `{ {}; }` + | -- ^^^^^^^ -- the attributes are attached to this branch | | | - | | expected `{` - | this `if` expression has a condition, but no block + | | help: remove the attributes + | the branch belongs to this `if` error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:58:51 + --> $DIR/attr-stmt-expr-attr-bad.rs:55:51 | LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. -error: attributes are not yet allowed on `if` expressions - --> $DIR/attr-stmt-expr-attr-bad.rs:60:32 - | -LL | #[cfg(FALSE)] fn e() { let _ = #[attr] if let _ = 0 {}; } - | ^^^^^^^ - -error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:62:45 +error: outer attributes are not allowed on `if` and `else` branches + --> $DIR/attr-stmt-expr-attr-bad.rs:57:45 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; } - | -- ^ --- help: try placing this code inside a block: `{ {}; }` + | -- ^^^^^^^ -- the attributes are attached to this branch | | | - | | expected `{` - | this `if` expression has a condition, but no block + | | help: remove the attributes + | the branch belongs to this `if` error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:64:46 + --> $DIR/attr-stmt-expr-attr-bad.rs:59:46 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } | ^^^^^^^^ @@ -236,52 +220,48 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; } = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:66:48 + --> $DIR/attr-stmt-expr-attr-bad.rs:61:48 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; } | ^ expected one of `.`, `;`, `?`, `else`, or an operator -error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:68:53 +error: outer attributes are not allowed on `if` and `else` branches + --> $DIR/attr-stmt-expr-attr-bad.rs:63:53 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; } - | ^ --- help: try placing this code inside a block: `{ {}; }` - | | - | expected `{` + | ---- ^^^^^^^ -- the attributes are attached to this branch + | | | + | | help: remove the attributes + | the branch belongs to this `else` error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:70:54 + --> $DIR/attr-stmt-expr-attr-bad.rs:65:54 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; } | ^^^^^^^^ | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. -error: attributes are not yet allowed on `if` expressions - --> $DIR/attr-stmt-expr-attr-bad.rs:72:53 +error: outer attributes are not allowed on `if` and `else` branches + --> $DIR/attr-stmt-expr-attr-bad.rs:67:53 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } - | ^^^^^^^ + | ---- ^^^^^^^ --------------- the attributes are attached to this branch + | | | + | | help: remove the attributes + | the branch belongs to this `else` -error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:72:53 - | -LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; } - | ^ ---------------- help: try placing this code inside a block: `{ if let _ = 0 {}; }` - | | - | expected `{` - -error: expected `{`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:75:66 +error: outer attributes are not allowed on `if` and `else` branches + --> $DIR/attr-stmt-expr-attr-bad.rs:69:66 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; } - | -- ^ --- help: try placing this code inside a block: `{ {}; }` + | -- ^^^^^^^ -- the attributes are attached to this branch | | | - | | expected `{` - | this `if` expression has a condition, but no block + | | help: remove the attributes + | the branch belongs to this `if` error: an inner attribute is not permitted in this context - --> $DIR/attr-stmt-expr-attr-bad.rs:77:67 + --> $DIR/attr-stmt-expr-attr-bad.rs:71:67 | LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; } | ^^^^^^^^ @@ -289,57 +269,57 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]} = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: an inner attribute is not permitted following an outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:80:32 + --> $DIR/attr-stmt-expr-attr-bad.rs:74:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; } - | ------- ^^^^^^^^ not permitted following an outer attibute + | ------- ^^^^^^^^ not permitted following an outer attribute | | | previous outer attribute | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: an inner attribute is not permitted following an outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:82:32 + --> $DIR/attr-stmt-expr-attr-bad.rs:76:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] 0; } - | ------- ^^^^^^^^ not permitted following an outer attibute + | ------- ^^^^^^^^ not permitted following an outer attribute | | | previous outer attribute | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: an inner attribute is not permitted following an outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:84:32 + --> $DIR/attr-stmt-expr-attr-bad.rs:78:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); } - | ------- ^^^^^^^^ not permitted following an outer attibute + | ------- ^^^^^^^^ not permitted following an outer attribute | | | previous outer attribute | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: an inner attribute is not permitted following an outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:86:32 + --> $DIR/attr-stmt-expr-attr-bad.rs:80:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; } - | ------- ^^^^^^^^ not permitted following an outer attibute + | ------- ^^^^^^^^ not permitted following an outer attribute | | | previous outer attribute | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error: an inner attribute is not permitted following an outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:88:32 + --> $DIR/attr-stmt-expr-attr-bad.rs:82:32 | LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; } - | ------- ^^^^^^^^ not permitted following an outer attibute + | ------- ^^^^^^^^ not permitted following an outer attribute | | | previous outer attribute | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. error[E0586]: inclusive range with no end - --> $DIR/attr-stmt-expr-attr-bad.rs:94:35 + --> $DIR/attr-stmt-expr-attr-bad.rs:88:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } | ^^^ help: use `..` instead @@ -347,13 +327,13 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) error: expected one of `=>`, `if`, or `|`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:94:38 + --> $DIR/attr-stmt-expr-attr-bad.rs:88:38 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } } | ^ expected one of `=>`, `if`, or `|` error[E0586]: inclusive range with no end - --> $DIR/attr-stmt-expr-attr-bad.rs:97:35 + --> $DIR/attr-stmt-expr-attr-bad.rs:91:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } | ^^^ help: use `..` instead @@ -361,19 +341,19 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) error: expected one of `=>`, `if`, or `|`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:97:38 + --> $DIR/attr-stmt-expr-attr-bad.rs:91:38 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } } | ^ expected one of `=>`, `if`, or `|` error: unexpected token: `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:100:39 + --> $DIR/attr-stmt-expr-attr-bad.rs:94:39 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } } | ^ error[E0586]: inclusive range with no end - --> $DIR/attr-stmt-expr-attr-bad.rs:102:35 + --> $DIR/attr-stmt-expr-attr-bad.rs:96:35 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } | ^^^ help: use `..` instead @@ -381,47 +361,47 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) error: expected one of `=>`, `if`, or `|`, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:102:38 + --> $DIR/attr-stmt-expr-attr-bad.rs:96:38 | LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } } | ^ expected one of `=>`, `if`, or `|` error: unexpected token: `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:106:34 + --> $DIR/attr-stmt-expr-attr-bad.rs:100:34 | LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } | ^ error: expected one of `.`, `;`, `?`, or an operator, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:106:34 + --> $DIR/attr-stmt-expr-attr-bad.rs:100:34 | LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); } | ^ expected one of `.`, `;`, `?`, or an operator error: unexpected token: `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:109:34 + --> $DIR/attr-stmt-expr-attr-bad.rs:103:34 | LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } | ^ error: expected one of `.`, `;`, `?`, or an operator, found `#` - --> $DIR/attr-stmt-expr-attr-bad.rs:109:34 + --> $DIR/attr-stmt-expr-attr-bad.rs:103:34 | LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); } | ^ expected one of `.`, `;`, `?`, or an operator error: expected statement after outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:114:44 + --> $DIR/attr-stmt-expr-attr-bad.rs:108:37 | LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } } - | ^ + | ^^^^^^^ error: expected statement after outer attribute - --> $DIR/attr-stmt-expr-attr-bad.rs:116:45 + --> $DIR/attr-stmt-expr-attr-bad.rs:110:37 | LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr] } } } - | ^ + | ^^^^^^^ -error: aborting due to 57 previous errors +error: aborting due to 53 previous errors For more information about this error, try `rustc --explain E0586`. diff --git a/src/test/ui/parser/attrs-after-extern-mod.rs b/src/test/ui/parser/attrs-after-extern-mod.rs index 4bdd16471cd..ea899dca7b2 100644 --- a/src/test/ui/parser/attrs-after-extern-mod.rs +++ b/src/test/ui/parser/attrs-after-extern-mod.rs @@ -1,13 +1,7 @@ -// Constants (static variables) can be used to match in patterns, but mutable -// statics cannot. This ensures that there's some form of error if this is -// attempted. +// Make sure there's an error when given `extern { ... #[attr] }`. -extern crate libc; +fn main() {} extern { - static mut rust_dbg_static_mut: libc::c_int; - pub fn rust_dbg_static_mut_check_four(); #[cfg(stage37)] //~ ERROR expected item after attributes } - -pub fn main() {} diff --git a/src/test/ui/parser/attrs-after-extern-mod.stderr b/src/test/ui/parser/attrs-after-extern-mod.stderr index cecdab4d631..3862f5c379f 100644 --- a/src/test/ui/parser/attrs-after-extern-mod.stderr +++ b/src/test/ui/parser/attrs-after-extern-mod.stderr @@ -1,8 +1,12 @@ error: expected item after attributes - --> $DIR/attrs-after-extern-mod.rs:10:19 + --> $DIR/attrs-after-extern-mod.rs:6:5 | +LL | extern { + | - while parsing this item list starting here LL | #[cfg(stage37)] - | ^ + | ^^^^^^^^^^^^^^^ +LL | } + | - the item list ends here error: aborting due to previous error diff --git a/src/test/ui/parser/bad-interpolated-block.rs b/src/test/ui/parser/bad-interpolated-block.rs new file mode 100644 index 00000000000..38d53a14bc0 --- /dev/null +++ b/src/test/ui/parser/bad-interpolated-block.rs @@ -0,0 +1,15 @@ +#![feature(label_break_value)] + +fn main() {} + +macro_rules! m { + ($b:block) => { + 'lab: $b; //~ ERROR cannot use a `block` macro fragment here + unsafe $b; //~ ERROR cannot use a `block` macro fragment here + |x: u8| -> () $b; //~ ERROR cannot use a `block` macro fragment here + } +} + +fn foo() { + m!({}); +} diff --git a/src/test/ui/parser/bad-interpolated-block.stderr b/src/test/ui/parser/bad-interpolated-block.stderr new file mode 100644 index 00000000000..2cbb6a13e74 --- /dev/null +++ b/src/test/ui/parser/bad-interpolated-block.stderr @@ -0,0 +1,39 @@ +error: cannot use a `block` macro fragment here + --> $DIR/bad-interpolated-block.rs:7:15 + | +LL | 'lab: $b; + | ------^^ + | | + | the `block` fragment is within this context +... +LL | m!({}); + | ------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot use a `block` macro fragment here + --> $DIR/bad-interpolated-block.rs:8:16 + | +LL | unsafe $b; + | -------^^ + | | + | the `block` fragment is within this context +... +LL | m!({}); + | ------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot use a `block` macro fragment here + --> $DIR/bad-interpolated-block.rs:9:23 + | +LL | |x: u8| -> () $b; + | ^^ the `block` fragment is within this context +... +LL | m!({}); + | ------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/block-no-opening-brace.rs b/src/test/ui/parser/block-no-opening-brace.rs new file mode 100644 index 00000000000..e4bb39f6836 --- /dev/null +++ b/src/test/ui/parser/block-no-opening-brace.rs @@ -0,0 +1,31 @@ +// edition:2018 + +#![feature(try_blocks)] + +fn main() {} + +fn f1() { + loop + let x = 0; //~ ERROR expected `{`, found keyword `let` + drop(0); + } + +fn f2() { + while true + let x = 0; //~ ERROR expected `{`, found keyword `let` + } + +fn f3() { + for x in 0..1 + let x = 0; //~ ERROR expected `{`, found keyword `let` + } + +fn f4() { + try //~ ERROR expected expression, found reserved keyword `try` + let x = 0; + } + +fn f5() { + async //~ ERROR async closures are unstable + let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let` + } diff --git a/src/test/ui/parser/block-no-opening-brace.stderr b/src/test/ui/parser/block-no-opening-brace.stderr new file mode 100644 index 00000000000..a88e4ac44cf --- /dev/null +++ b/src/test/ui/parser/block-no-opening-brace.stderr @@ -0,0 +1,53 @@ +error: expected `{`, found keyword `let` + --> $DIR/block-no-opening-brace.rs:9:9 + | +LL | let x = 0; + | ^^^------- + | | + | expected `{` + | help: try placing this code inside a block: `{ let x = 0; }` + +error: expected `{`, found keyword `let` + --> $DIR/block-no-opening-brace.rs:15:9 + | +LL | let x = 0; + | ^^^------- + | | + | expected `{` + | help: try placing this code inside a block: `{ let x = 0; }` + +error: expected `{`, found keyword `let` + --> $DIR/block-no-opening-brace.rs:20:9 + | +LL | let x = 0; + | ^^^------- + | | + | expected `{` + | help: try placing this code inside a block: `{ let x = 0; }` + +error: expected expression, found reserved keyword `try` + --> $DIR/block-no-opening-brace.rs:24:5 + | +LL | try + | ^^^ expected expression + +error: expected one of `move`, `|`, or `||`, found keyword `let` + --> $DIR/block-no-opening-brace.rs:30:9 + | +LL | async + | - expected one of `move`, `|`, or `||` +LL | let x = 0; + | ^^^ unexpected token + +error[E0658]: async closures are unstable + --> $DIR/block-no-opening-brace.rs:29:5 + | +LL | async + | ^^^^^ + | + = note: see issue #62290 for more information + = help: add `#![feature(async_closure)]` to the crate attributes to enable + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/parser/bounds-lifetime-where.rs b/src/test/ui/parser/bounds-lifetime-where.rs index acb04e7859b..e60cc153e67 100644 --- a/src/test/ui/parser/bounds-lifetime-where.rs +++ b/src/test/ui/parser/bounds-lifetime-where.rs @@ -5,6 +5,6 @@ type A where 'a:, = u8; // OK type A where 'a: 'b + 'c = u8; // OK type A where = u8; // OK type A where 'a: 'b + = u8; // OK -type A where , = u8; //~ ERROR expected one of `=`, lifetime, or type, found `,` +type A where , = u8; //~ ERROR expected one of `;`, `=`, lifetime, or type, found `,` fn main() {} diff --git a/src/test/ui/parser/bounds-lifetime-where.stderr b/src/test/ui/parser/bounds-lifetime-where.stderr index 05cebd6d351..950fa46c66b 100644 --- a/src/test/ui/parser/bounds-lifetime-where.stderr +++ b/src/test/ui/parser/bounds-lifetime-where.stderr @@ -1,8 +1,8 @@ -error: expected one of `=`, lifetime, or type, found `,` +error: expected one of `;`, `=`, lifetime, or type, found `,` --> $DIR/bounds-lifetime-where.rs:8:14 | LL | type A where , = u8; - | ^ expected one of `=`, lifetime, or type + | ^ expected one of `;`, `=`, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/parser/bounds-lifetime.rs b/src/test/ui/parser/bounds-lifetime.rs index 9225cfce94e..c9251ac5321 100644 --- a/src/test/ui/parser/bounds-lifetime.rs +++ b/src/test/ui/parser/bounds-lifetime.rs @@ -6,6 +6,6 @@ type A = for<'a: 'b + 'c> fn(); // OK (rejected later by ast_validation) type A = for<'a: 'b,> fn(); // OK(rejected later by ast_validation) type A = for<'a: 'b +> fn(); // OK (rejected later by ast_validation) type A = for<'a, T> fn(); // OK (rejected later by ast_validation) -type A = for<,> fn(); //~ ERROR expected one of `>`, `const`, identifier, or lifetime, found `,` +type A = for<,> fn(); //~ ERROR expected one of `#`, `>`, `const`, identifier, or lifetime fn main() {} diff --git a/src/test/ui/parser/bounds-lifetime.stderr b/src/test/ui/parser/bounds-lifetime.stderr index 12b9b61ebd1..e47a21d892b 100644 --- a/src/test/ui/parser/bounds-lifetime.stderr +++ b/src/test/ui/parser/bounds-lifetime.stderr @@ -1,8 +1,8 @@ -error: expected one of `>`, `const`, identifier, or lifetime, found `,` +error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` --> $DIR/bounds-lifetime.rs:9:14 | LL | type A = for<,> fn(); - | ^ expected one of `>`, `const`, identifier, or lifetime + | ^ expected one of `#`, `>`, `const`, identifier, or lifetime error: aborting due to previous error diff --git a/src/test/ui/parser/circular_modules_main.rs b/src/test/ui/parser/circular_modules_main.rs index b85003bf091..1ae36a1f760 100644 --- a/src/test/ui/parser/circular_modules_main.rs +++ b/src/test/ui/parser/circular_modules_main.rs @@ -6,5 +6,5 @@ pub fn hi_str() -> String { } fn main() { - circular_modules_hello::say_hello(); + circular_modules_hello::say_hello(); //~ ERROR cannot find function `say_hello` in module } diff --git a/src/test/ui/parser/circular_modules_main.stderr b/src/test/ui/parser/circular_modules_main.stderr index 33865fb7bca..90f81c64835 100644 --- a/src/test/ui/parser/circular_modules_main.stderr +++ b/src/test/ui/parser/circular_modules_main.stderr @@ -1,8 +1,20 @@ error: circular modules: $DIR/circular_modules_hello.rs -> $DIR/circular_modules_main.rs -> $DIR/circular_modules_hello.rs - --> $DIR/circular_modules_main.rs:2:5 + --> $DIR/circular_modules_main.rs:2:1 | LL | mod circular_modules_hello; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0425]: cannot find function `say_hello` in module `circular_modules_hello` + --> $DIR/circular_modules_main.rs:9:29 + | +LL | circular_modules_hello::say_hello(); + | ^^^^^^^^^ not found in `circular_modules_hello` + | +help: possible candidate is found in another module, you can import it into scope + | +LL | use circular_modules_hello::say_hello; + | + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/parser/closure-return-syntax.rs b/src/test/ui/parser/closure-return-syntax.rs index 54eb791d2bc..c6a08abeff4 100644 --- a/src/test/ui/parser/closure-return-syntax.rs +++ b/src/test/ui/parser/closure-return-syntax.rs @@ -3,5 +3,5 @@ fn main() { let x = || -> i32 22; - //~^ ERROR expected one of `!`, `(`, `+`, `::`, `<`, or `{`, found `22` + //~^ ERROR expected `{`, found `22` } diff --git a/src/test/ui/parser/closure-return-syntax.stderr b/src/test/ui/parser/closure-return-syntax.stderr index bfb7f98c5f5..1ccdd977305 100644 --- a/src/test/ui/parser/closure-return-syntax.stderr +++ b/src/test/ui/parser/closure-return-syntax.stderr @@ -1,8 +1,11 @@ -error: expected one of `!`, `(`, `+`, `::`, `<`, or `{`, found `22` +error: expected `{`, found `22` --> $DIR/closure-return-syntax.rs:5:23 | LL | let x = || -> i32 22; - | ^^ expected one of `!`, `(`, `+`, `::`, `<`, or `{` + | ^^ + | | + | expected `{` + | help: try placing this code inside a block: `{ 22 }` error: aborting due to previous error diff --git a/src/test/ui/parser/column-offset-1-based.rs b/src/test/ui/parser/column-offset-1-based.rs index e158e5247db..0c24478c25c 100644 --- a/src/test/ui/parser/column-offset-1-based.rs +++ b/src/test/ui/parser/column-offset-1-based.rs @@ -1 +1 @@ -# //~ ERROR expected `[`, found `` +# //~ ERROR expected one of `!` or `[`, found `` diff --git a/src/test/ui/parser/column-offset-1-based.stderr b/src/test/ui/parser/column-offset-1-based.stderr index 5cbf3d3e959..766d72a0a5a 100644 --- a/src/test/ui/parser/column-offset-1-based.stderr +++ b/src/test/ui/parser/column-offset-1-based.stderr @@ -1,8 +1,8 @@ -error: expected `[`, found `` +error: expected one of `!` or `[`, found `` --> $DIR/column-offset-1-based.rs:1:1 | LL | # - | ^ expected `[` + | ^ expected one of `!` or `[` error: aborting due to previous error diff --git a/src/test/ui/parser/default-on-wrong-item-kind.rs b/src/test/ui/parser/default-on-wrong-item-kind.rs new file mode 100644 index 00000000000..98a95cfa35a --- /dev/null +++ b/src/test/ui/parser/default-on-wrong-item-kind.rs @@ -0,0 +1,140 @@ +// Test parsing for `default` where it doesn't belong. +// Specifically, we are interested in kinds of items or items in certain contexts. +// Also test item kinds in `extern` blocks and associated contexts which are not allowed there. + +fn main() {} + +#[cfg(FALSE)] +mod free_items { + default extern crate foo; //~ ERROR an extern crate cannot be `default` + default use foo; //~ ERROR a `use` import cannot be `default` + default static foo: u8; //~ ERROR a static item cannot be `default` + default const foo: u8; + default fn foo(); + default mod foo {} //~ ERROR a module cannot be `default` + default extern "C" {} //~ ERROR an extern block cannot be `default` + default type foo = u8; + default enum foo {} //~ ERROR an enum cannot be `default` + default struct foo {} //~ ERROR a struct cannot be `default` + default union foo {} //~ ERROR a union cannot be `default` + default trait foo {} //~ ERROR a trait cannot be `default` + default trait foo = Ord; //~ ERROR a trait alias cannot be `default` + default impl foo {} + default!(); + default::foo::bar!(); + default default!(); //~ ERROR an item macro invocation cannot be `default` + default default::foo::bar!(); //~ ERROR an item macro invocation cannot be `default` + default macro foo {} //~ ERROR a macro definition cannot be `default` + default macro_rules! foo {} //~ ERROR a macro definition cannot be `default` +} + +#[cfg(FALSE)] +extern "C" { + default extern crate foo; //~ ERROR an extern crate cannot be `default` + //~^ ERROR extern crate is not supported in `extern` blocks + default use foo; //~ ERROR a `use` import cannot be `default` + //~^ ERROR `use` import is not supported in `extern` blocks + default static foo: u8; //~ ERROR a static item cannot be `default` + default const foo: u8; + //~^ ERROR extern items cannot be `const` + default fn foo(); + default mod foo {} //~ ERROR a module cannot be `default` + //~^ ERROR module is not supported in `extern` blocks + default extern "C" {} //~ ERROR an extern block cannot be `default` + //~^ ERROR extern block is not supported in `extern` blocks + default type foo = u8; + default enum foo {} //~ ERROR an enum cannot be `default` + //~^ ERROR enum is not supported in `extern` blocks + default struct foo {} //~ ERROR a struct cannot be `default` + //~^ ERROR struct is not supported in `extern` blocks + default union foo {} //~ ERROR a union cannot be `default` + //~^ ERROR union is not supported in `extern` blocks + default trait foo {} //~ ERROR a trait cannot be `default` + //~^ ERROR trait is not supported in `extern` blocks + default trait foo = Ord; //~ ERROR a trait alias cannot be `default` + //~^ ERROR trait alias is not supported in `extern` blocks + default impl foo {} + //~^ ERROR implementation is not supported in `extern` blocks + default!(); + default::foo::bar!(); + default default!(); //~ ERROR an item macro invocation cannot be `default` + default default::foo::bar!(); //~ ERROR an item macro invocation cannot be `default` + default macro foo {} //~ ERROR a macro definition cannot be `default` + //~^ ERROR macro definition is not supported in `extern` blocks + default macro_rules! foo {} //~ ERROR a macro definition cannot be `default` + //~^ ERROR macro definition is not supported in `extern` blocks +} + +#[cfg(FALSE)] +impl S { + default extern crate foo; //~ ERROR an extern crate cannot be `default` + //~^ ERROR extern crate is not supported in `trait`s or `impl`s + default use foo; //~ ERROR a `use` import cannot be `default` + //~^ ERROR `use` import is not supported in `trait`s or `impl`s + default static foo: u8; //~ ERROR a static item cannot be `default` + //~^ ERROR associated `static` items are not allowed + default const foo: u8; + default fn foo(); + default mod foo {}//~ ERROR a module cannot be `default` + //~^ ERROR module is not supported in `trait`s or `impl`s + default extern "C" {} //~ ERROR an extern block cannot be `default` + //~^ ERROR extern block is not supported in `trait`s or `impl`s + default type foo = u8; + default enum foo {} //~ ERROR an enum cannot be `default` + //~^ ERROR enum is not supported in `trait`s or `impl`s + default struct foo {} //~ ERROR a struct cannot be `default` + //~^ ERROR struct is not supported in `trait`s or `impl`s + default union foo {} //~ ERROR a union cannot be `default` + //~^ ERROR union is not supported in `trait`s or `impl`s + default trait foo {} //~ ERROR a trait cannot be `default` + //~^ ERROR trait is not supported in `trait`s or `impl`s + default trait foo = Ord; //~ ERROR a trait alias cannot be `default` + //~^ ERROR trait alias is not supported in `trait`s or `impl`s + default impl foo {} + //~^ ERROR implementation is not supported in `trait`s or `impl`s + default!(); + default::foo::bar!(); + default default!(); //~ ERROR an item macro invocation cannot be `default` + default default::foo::bar!(); //~ ERROR an item macro invocation cannot be `default` + default macro foo {} //~ ERROR a macro definition cannot be `default` + //~^ ERROR macro definition is not supported in `trait`s or `impl`s + default macro_rules! foo {} //~ ERROR a macro definition cannot be `default` + //~^ ERROR macro definition is not supported in `trait`s or `impl`s +} + +#[cfg(FALSE)] +trait T { + default extern crate foo; //~ ERROR an extern crate cannot be `default` + //~^ ERROR extern crate is not supported in `trait`s or `impl`s + default use foo; //~ ERROR a `use` import cannot be `default` + //~^ ERROR `use` import is not supported in `trait`s or `impl`s + default static foo: u8; //~ ERROR a static item cannot be `default` + //~^ ERROR associated `static` items are not allowed + default const foo: u8; + default fn foo(); + default mod foo {}//~ ERROR a module cannot be `default` + //~^ ERROR module is not supported in `trait`s or `impl`s + default extern "C" {} //~ ERROR an extern block cannot be `default` + //~^ ERROR extern block is not supported in `trait`s or `impl`s + default type foo = u8; + default enum foo {} //~ ERROR an enum cannot be `default` + //~^ ERROR enum is not supported in `trait`s or `impl`s + default struct foo {} //~ ERROR a struct cannot be `default` + //~^ ERROR struct is not supported in `trait`s or `impl`s + default union foo {} //~ ERROR a union cannot be `default` + //~^ ERROR union is not supported in `trait`s or `impl`s + default trait foo {} //~ ERROR a trait cannot be `default` + //~^ ERROR trait is not supported in `trait`s or `impl`s + default trait foo = Ord; //~ ERROR a trait alias cannot be `default` + //~^ ERROR trait alias is not supported in `trait`s or `impl`s + default impl foo {} + //~^ ERROR implementation is not supported in `trait`s or `impl`s + default!(); + default::foo::bar!(); + default default!(); //~ ERROR an item macro invocation cannot be `default` + default default::foo::bar!(); //~ ERROR an item macro invocation cannot be `default` + default macro foo {} //~ ERROR a macro definition cannot be `default` + //~^ ERROR macro definition is not supported in `trait`s or `impl`s + default macro_rules! foo {} //~ ERROR a macro definition cannot be `default` + //~^ ERROR macro definition is not supported in `trait`s or `impl`s +} diff --git a/src/test/ui/parser/default-on-wrong-item-kind.stderr b/src/test/ui/parser/default-on-wrong-item-kind.stderr new file mode 100644 index 00000000000..9788bd64725 --- /dev/null +++ b/src/test/ui/parser/default-on-wrong-item-kind.stderr @@ -0,0 +1,688 @@ +error: an extern crate cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:9:5 + | +LL | default extern crate foo; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a `use` import cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:10:5 + | +LL | default use foo; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a static item cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:11:5 + | +LL | default static foo: u8; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a module cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:14:5 + | +LL | default mod foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: an extern block cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:15:5 + | +LL | default extern "C" {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: an enum cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:17:5 + | +LL | default enum foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a struct cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:18:5 + | +LL | default struct foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a union cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:19:5 + | +LL | default union foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a trait cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:20:5 + | +LL | default trait foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a trait alias cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:21:5 + | +LL | default trait foo = Ord; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: an item macro invocation cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:25:5 + | +LL | default default!(); + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: an item macro invocation cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:26:5 + | +LL | default default::foo::bar!(); + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a macro definition cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:27:5 + | +LL | default macro foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a macro definition cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:28:5 + | +LL | default macro_rules! foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: an extern crate cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:33:5 + | +LL | default extern crate foo; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: extern crate is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:33:5 + | +LL | default extern crate foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `use` import cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:35:5 + | +LL | default use foo; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: `use` import is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:35:5 + | +LL | default use foo; + | ^^^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:37:5 + | +LL | default static foo: u8; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: extern items cannot be `const` + --> $DIR/default-on-wrong-item-kind.rs:38:19 + | +LL | default const foo: u8; + | --------------^^^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: a module cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:41:5 + | +LL | default mod foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: module is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:41:5 + | +LL | default mod foo {} + | ^^^^^^^^^^^^^^^ + +error: an extern block cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:43:5 + | +LL | default extern "C" {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: extern block is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:43:5 + | +LL | default extern "C" {} + | ^^^^^^^^^^^^^^^^^^ + +error: an enum cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:46:5 + | +LL | default enum foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: enum is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:46:5 + | +LL | default enum foo {} + | ^^^^^^^^^^^^^^^^ + +error: a struct cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:48:5 + | +LL | default struct foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: struct is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:48:5 + | +LL | default struct foo {} + | ^^^^^^^^^^^^^^^^^^ + +error: a union cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:50:5 + | +LL | default union foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: union is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:50:5 + | +LL | default union foo {} + | ^^^^^^^^^^^^^^^^^ + +error: a trait cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:52:5 + | +LL | default trait foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: trait is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:52:5 + | +LL | default trait foo {} + | ^^^^^^^^^^^^^^^^^ + +error: a trait alias cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:54:5 + | +LL | default trait foo = Ord; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: trait alias is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:54:5 + | +LL | default trait foo = Ord; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: implementation is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:56:5 + | +LL | default impl foo {} + | ^^^^^^^^^^^^^^^^ + +error: an item macro invocation cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:60:5 + | +LL | default default!(); + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: an item macro invocation cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:61:5 + | +LL | default default::foo::bar!(); + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a macro definition cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:62:5 + | +LL | default macro foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: macro definition is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:62:5 + | +LL | default macro foo {} + | ^^^^^^^^^^^^^^^^^ + +error: a macro definition cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:64:5 + | +LL | default macro_rules! foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: macro definition is not supported in `extern` blocks + --> $DIR/default-on-wrong-item-kind.rs:64:5 + | +LL | default macro_rules! foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: an extern crate cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:70:5 + | +LL | default extern crate foo; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: extern crate is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:70:5 + | +LL | default extern crate foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `use` import cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:72:5 + | +LL | default use foo; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: `use` import is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:72:5 + | +LL | default use foo; + | ^^^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:74:5 + | +LL | default static foo: u8; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/default-on-wrong-item-kind.rs:74:5 + | +LL | default static foo: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: a module cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:78:5 + | +LL | default mod foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: module is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:78:5 + | +LL | default mod foo {} + | ^^^^^^^^^^^^^^^ + +error: an extern block cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:80:5 + | +LL | default extern "C" {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: extern block is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:80:5 + | +LL | default extern "C" {} + | ^^^^^^^^^^^^^^^^^^ + +error: an enum cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:83:5 + | +LL | default enum foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: enum is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:83:5 + | +LL | default enum foo {} + | ^^^^^^^^^^^^^^^^ + +error: a struct cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:85:5 + | +LL | default struct foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: struct is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:85:5 + | +LL | default struct foo {} + | ^^^^^^^^^^^^^^^^^^ + +error: a union cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:87:5 + | +LL | default union foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: union is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:87:5 + | +LL | default union foo {} + | ^^^^^^^^^^^^^^^^^ + +error: a trait cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:89:5 + | +LL | default trait foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: trait is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:89:5 + | +LL | default trait foo {} + | ^^^^^^^^^^^^^^^^^ + +error: a trait alias cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:91:5 + | +LL | default trait foo = Ord; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: trait alias is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:91:5 + | +LL | default trait foo = Ord; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: implementation is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:93:5 + | +LL | default impl foo {} + | ^^^^^^^^^^^^^^^^ + +error: an item macro invocation cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:97:5 + | +LL | default default!(); + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: an item macro invocation cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:98:5 + | +LL | default default::foo::bar!(); + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a macro definition cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:99:5 + | +LL | default macro foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: macro definition is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:99:5 + | +LL | default macro foo {} + | ^^^^^^^^^^^^^^^^^ + +error: a macro definition cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:101:5 + | +LL | default macro_rules! foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: macro definition is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:101:5 + | +LL | default macro_rules! foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: an extern crate cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:107:5 + | +LL | default extern crate foo; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: extern crate is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:107:5 + | +LL | default extern crate foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `use` import cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:109:5 + | +LL | default use foo; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: `use` import is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:109:5 + | +LL | default use foo; + | ^^^^^^^^^^^^^^^^ + +error: a static item cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:111:5 + | +LL | default static foo: u8; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: associated `static` items are not allowed + --> $DIR/default-on-wrong-item-kind.rs:111:5 + | +LL | default static foo: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: a module cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:115:5 + | +LL | default mod foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: module is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:115:5 + | +LL | default mod foo {} + | ^^^^^^^^^^^^^^^ + +error: an extern block cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:117:5 + | +LL | default extern "C" {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: extern block is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:117:5 + | +LL | default extern "C" {} + | ^^^^^^^^^^^^^^^^^^ + +error: an enum cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:120:5 + | +LL | default enum foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: enum is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:120:5 + | +LL | default enum foo {} + | ^^^^^^^^^^^^^^^^ + +error: a struct cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:122:5 + | +LL | default struct foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: struct is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:122:5 + | +LL | default struct foo {} + | ^^^^^^^^^^^^^^^^^^ + +error: a union cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:124:5 + | +LL | default union foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: union is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:124:5 + | +LL | default union foo {} + | ^^^^^^^^^^^^^^^^^ + +error: a trait cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:126:5 + | +LL | default trait foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: trait is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:126:5 + | +LL | default trait foo {} + | ^^^^^^^^^^^^^^^^^ + +error: a trait alias cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:128:5 + | +LL | default trait foo = Ord; + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: trait alias is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:128:5 + | +LL | default trait foo = Ord; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: implementation is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:130:5 + | +LL | default impl foo {} + | ^^^^^^^^^^^^^^^^ + +error: an item macro invocation cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:134:5 + | +LL | default default!(); + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: an item macro invocation cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:135:5 + | +LL | default default::foo::bar!(); + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: a macro definition cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:136:5 + | +LL | default macro foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: macro definition is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:136:5 + | +LL | default macro foo {} + | ^^^^^^^^^^^^^^^^^ + +error: a macro definition cannot be `default` + --> $DIR/default-on-wrong-item-kind.rs:138:5 + | +LL | default macro_rules! foo {} + | ^^^^^^^ `default` because of this + | + = note: only associated `fn`, `const`, and `type` items can be `default` + +error: macro definition is not supported in `trait`s or `impl`s + --> $DIR/default-on-wrong-item-kind.rs:138:5 + | +LL | default macro_rules! foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 95 previous errors + diff --git a/src/test/ui/parser/default-unmatched-assoc.rs b/src/test/ui/parser/default-unmatched-assoc.rs new file mode 100644 index 00000000000..168ea3e76f6 --- /dev/null +++ b/src/test/ui/parser/default-unmatched-assoc.rs @@ -0,0 +1,16 @@ +fn main() {} + +trait Foo { + default!(); //~ ERROR cannot find macro `default` in this scope + default do + //~^ ERROR `default` is not followed by an item + //~| ERROR non-item in item list +} + +struct S; +impl S { + default!(); //~ ERROR cannot find macro `default` in this scope + default do + //~^ ERROR `default` is not followed by an item + //~| ERROR non-item in item list +} diff --git a/src/test/ui/parser/default-unmatched-assoc.stderr b/src/test/ui/parser/default-unmatched-assoc.stderr new file mode 100644 index 00000000000..c8d1769cb5a --- /dev/null +++ b/src/test/ui/parser/default-unmatched-assoc.stderr @@ -0,0 +1,54 @@ +error: `default` is not followed by an item + --> $DIR/default-unmatched-assoc.rs:5:5 + | +LL | default do + | ^^^^^^^ the `default` qualifier + | + = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` + +error: non-item in item list + --> $DIR/default-unmatched-assoc.rs:5:13 + | +LL | trait Foo { + | - item list starts here +LL | default!(); +LL | default do + | ^^ non-item starts here +... +LL | } + | - item list ends here + +error: `default` is not followed by an item + --> $DIR/default-unmatched-assoc.rs:13:5 + | +LL | default do + | ^^^^^^^ the `default` qualifier + | + = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` + +error: non-item in item list + --> $DIR/default-unmatched-assoc.rs:13:13 + | +LL | impl S { + | - item list starts here +LL | default!(); +LL | default do + | ^^ non-item starts here +... +LL | } + | - item list ends here + +error: cannot find macro `default` in this scope + --> $DIR/default-unmatched-assoc.rs:12:5 + | +LL | default!(); + | ^^^^^^^ + +error: cannot find macro `default` in this scope + --> $DIR/default-unmatched-assoc.rs:4:5 + | +LL | default!(); + | ^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/parser/default-unmatched-extern.rs b/src/test/ui/parser/default-unmatched-extern.rs new file mode 100644 index 00000000000..8d0ea590f57 --- /dev/null +++ b/src/test/ui/parser/default-unmatched-extern.rs @@ -0,0 +1,8 @@ +fn main() {} + +extern "C" { + default!(); //~ ERROR cannot find macro `default` in this scope + default do + //~^ ERROR `default` is not followed by an item + //~| ERROR non-item in item list +} diff --git a/src/test/ui/parser/default-unmatched-extern.stderr b/src/test/ui/parser/default-unmatched-extern.stderr new file mode 100644 index 00000000000..bb4efd51631 --- /dev/null +++ b/src/test/ui/parser/default-unmatched-extern.stderr @@ -0,0 +1,28 @@ +error: `default` is not followed by an item + --> $DIR/default-unmatched-extern.rs:5:5 + | +LL | default do + | ^^^^^^^ the `default` qualifier + | + = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` + +error: non-item in item list + --> $DIR/default-unmatched-extern.rs:5:13 + | +LL | extern "C" { + | - item list starts here +LL | default!(); +LL | default do + | ^^ non-item starts here +... +LL | } + | - item list ends here + +error: cannot find macro `default` in this scope + --> $DIR/default-unmatched-extern.rs:4:5 + | +LL | default!(); + | ^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/default-unmatched.rs b/src/test/ui/parser/default-unmatched.rs new file mode 100644 index 00000000000..49346e5c631 --- /dev/null +++ b/src/test/ui/parser/default-unmatched.rs @@ -0,0 +1,6 @@ +mod foo { + default!(); // OK. + default do + //~^ ERROR `default` is not followed by an item + //~| ERROR expected item, found reserved keyword `do` +} diff --git a/src/test/ui/parser/default-unmatched.stderr b/src/test/ui/parser/default-unmatched.stderr new file mode 100644 index 00000000000..331e003f63c --- /dev/null +++ b/src/test/ui/parser/default-unmatched.stderr @@ -0,0 +1,16 @@ +error: `default` is not followed by an item + --> $DIR/default-unmatched.rs:3:5 + | +LL | default do + | ^^^^^^^ the `default` qualifier + | + = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` + +error: expected item, found reserved keyword `do` + --> $DIR/default-unmatched.rs:3:13 + | +LL | default do + | ^^ expected item + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/default.rs b/src/test/ui/parser/default.rs index 17cd06864bf..64ba4b55311 100644 --- a/src/test/ui/parser/default.rs +++ b/src/test/ui/parser/default.rs @@ -19,7 +19,9 @@ impl Foo for u16 { } impl Foo for u32 { //~ ERROR not all trait items implemented, missing: `foo` - default pub fn foo() -> T { T::default() } //~ ERROR expected one of + default pub fn foo() -> T { T::default() } + //~^ ERROR `default` is not followed by an item + //~| ERROR non-item in item list } fn main() {} diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr index dde36cf8dde..15c49e8b627 100644 --- a/src/test/ui/parser/default.stderr +++ b/src/test/ui/parser/default.stderr @@ -1,8 +1,21 @@ -error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found keyword `pub` +error: `default` is not followed by an item + --> $DIR/default.rs:22:5 + | +LL | default pub fn foo() -> T { T::default() } + | ^^^^^^^ the `default` qualifier + | + = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` + +error: non-item in item list --> $DIR/default.rs:22:13 | +LL | impl Foo for u32 { + | - item list starts here LL | default pub fn foo() -> T { T::default() } - | ^^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe` + | ^^^ non-item starts here +... +LL | } + | - item list ends here error[E0449]: unnecessary visibility qualifier --> $DIR/default.rs:16:5 @@ -19,7 +32,7 @@ LL | fn foo() -> T; LL | impl Foo for u32 { | ^^^^^^^^^^^^^^^^ missing `foo` in implementation -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0046, E0449. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/parser/doc-before-attr.stderr b/src/test/ui/parser/doc-before-attr.stderr index 0fae44ce5c8..14fd01af2f9 100644 --- a/src/test/ui/parser/doc-before-attr.stderr +++ b/src/test/ui/parser/doc-before-attr.stderr @@ -1,8 +1,10 @@ error: expected item after attributes - --> $DIR/doc-before-attr.rs:4:16 + --> $DIR/doc-before-attr.rs:4:1 | +LL | /// hi + | ------ other attributes here LL | #[derive(Debug)] - | ^ + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/doc-before-extern-rbrace.rs b/src/test/ui/parser/doc-before-extern-rbrace.rs index 695d4da1dca..040206b80ff 100644 --- a/src/test/ui/parser/doc-before-extern-rbrace.rs +++ b/src/test/ui/parser/doc-before-extern-rbrace.rs @@ -1,4 +1,6 @@ +fn main() {} + extern { /// hi - //~^ ERROR expected item after doc comment + //~^ ERROR found a documentation comment that doesn't document anything } diff --git a/src/test/ui/parser/doc-before-extern-rbrace.stderr b/src/test/ui/parser/doc-before-extern-rbrace.stderr index 8cc9c916a7a..0edceb268a7 100644 --- a/src/test/ui/parser/doc-before-extern-rbrace.stderr +++ b/src/test/ui/parser/doc-before-extern-rbrace.stderr @@ -1,8 +1,11 @@ -error: expected item after doc comment - --> $DIR/doc-before-extern-rbrace.rs:2:5 +error[E0584]: found a documentation comment that doesn't document anything + --> $DIR/doc-before-extern-rbrace.rs:4:5 | LL | /// hi | ^^^^^^ this doc comment doesn't document anything + | + = help: doc comments must come before what they document, maybe a comment was intended with `//`? error: aborting due to previous error +For more information about this error, try `rustc --explain E0584`. diff --git a/src/test/ui/parser/doc-before-semi.rs b/src/test/ui/parser/doc-before-semi.rs index c3f478fe420..405a7e1e2a3 100644 --- a/src/test/ui/parser/doc-before-semi.rs +++ b/src/test/ui/parser/doc-before-semi.rs @@ -3,6 +3,4 @@ fn main() { //~^ ERROR found a documentation comment that doesn't document anything //~| HELP maybe a comment was intended ; - //~^ WARNING unnecessary trailing semicolon - //~| HELP remove this semicolon } diff --git a/src/test/ui/parser/doc-before-semi.stderr b/src/test/ui/parser/doc-before-semi.stderr index b9ac30b09b2..e6bade18d0a 100644 --- a/src/test/ui/parser/doc-before-semi.stderr +++ b/src/test/ui/parser/doc-before-semi.stderr @@ -6,14 +6,6 @@ LL | /// hi | = help: doc comments must come before what they document, maybe a comment was intended with `//`? -warning: unnecessary trailing semicolon - --> $DIR/doc-before-semi.rs:5:5 - | -LL | ; - | ^ help: remove this semicolon - | - = note: `#[warn(redundant_semicolon)]` on by default - error: aborting due to previous error For more information about this error, try `rustc --explain E0585`. diff --git a/src/test/ui/parser/doc-comment-in-if-statement.rs b/src/test/ui/parser/doc-comment-in-if-statement.rs index c85fe25a7d0..343eac1b81f 100644 --- a/src/test/ui/parser/doc-comment-in-if-statement.rs +++ b/src/test/ui/parser/doc-comment-in-if-statement.rs @@ -1,4 +1,5 @@ fn main() { if true /*!*/ {} - //~^ ERROR expected `{`, found doc comment `/*!*/` + //~^ ERROR outer attributes are not allowed on + //~| ERROR expected outer doc comment } diff --git a/src/test/ui/parser/doc-comment-in-if-statement.stderr b/src/test/ui/parser/doc-comment-in-if-statement.stderr index a720dd68bd0..af21b78733f 100644 --- a/src/test/ui/parser/doc-comment-in-if-statement.stderr +++ b/src/test/ui/parser/doc-comment-in-if-statement.stderr @@ -1,10 +1,19 @@ -error: expected `{`, found doc comment `/*!*/` +error: expected outer doc comment --> $DIR/doc-comment-in-if-statement.rs:2:13 | LL | if true /*!*/ {} - | -- ^^^^^ expected `{` - | | - | this `if` expression has a condition, but no block + | ^^^^^ + | + = note: inner doc comments like this (starting with `//!` or `/*!`) can only appear before items + +error: outer attributes are not allowed on `if` and `else` branches + --> $DIR/doc-comment-in-if-statement.rs:2:13 + | +LL | if true /*!*/ {} + | -- ^^^^^ -- the attributes are attached to this branch + | | | + | | help: remove the attributes + | the branch belongs to this `if` -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/doc-inside-trait-item.stderr b/src/test/ui/parser/doc-inside-trait-item.stderr index 261e27b6e0d..246255a0a46 100644 --- a/src/test/ui/parser/doc-inside-trait-item.stderr +++ b/src/test/ui/parser/doc-inside-trait-item.stderr @@ -2,7 +2,7 @@ error[E0584]: found a documentation comment that doesn't document anything --> $DIR/doc-inside-trait-item.rs:3:5 | LL | /// empty doc - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ this doc comment doesn't document anything | = help: doc comments must come before what they document, maybe a comment was intended with `//`? diff --git a/src/test/ui/parser/duplicate-visibility.rs b/src/test/ui/parser/duplicate-visibility.rs index a8f0b7d61b9..31318ae3a09 100644 --- a/src/test/ui/parser/duplicate-visibility.rs +++ b/src/test/ui/parser/duplicate-visibility.rs @@ -1,4 +1,7 @@ -// error-pattern: expected one of `(`, `async`, `const`, `extern`, `fn` +fn main() {} + extern { pub pub fn foo(); + //~^ ERROR visibility `pub` is not followed by an item + //~| ERROR non-item in item list } diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr index cba4058e482..36b9efd9dca 100644 --- a/src/test/ui/parser/duplicate-visibility.stderr +++ b/src/test/ui/parser/duplicate-visibility.stderr @@ -1,8 +1,21 @@ -error: expected one of `(`, `async`, `const`, `extern`, `fn`, `static`, `type`, or `unsafe`, found keyword `pub` - --> $DIR/duplicate-visibility.rs:3:9 +error: visibility `pub` is not followed by an item + --> $DIR/duplicate-visibility.rs:4:5 | LL | pub pub fn foo(); - | ^^^ expected one of 8 possible tokens + | ^^^ the visibility + | + = help: you likely meant to define an item, e.g., `pub fn foo() {}` + +error: non-item in item list + --> $DIR/duplicate-visibility.rs:4:9 + | +LL | extern { + | - item list starts here +LL | pub pub fn foo(); + | ^^^ non-item starts here +... +LL | } + | - item list ends here -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/extern-no-fn.rs b/src/test/ui/parser/extern-no-fn.rs index c37ddd69ce5..d9f35e0eb5c 100644 --- a/src/test/ui/parser/extern-no-fn.rs +++ b/src/test/ui/parser/extern-no-fn.rs @@ -1,5 +1,5 @@ -extern { //~ ERROR missing `fn`, `type`, or `static` for extern-item declaration - f(); +extern { + f(); //~ ERROR expected one of `!` or `::`, found `(` } fn main() { diff --git a/src/test/ui/parser/extern-no-fn.stderr b/src/test/ui/parser/extern-no-fn.stderr index d2d5e3c4687..0151cb4235b 100644 --- a/src/test/ui/parser/extern-no-fn.stderr +++ b/src/test/ui/parser/extern-no-fn.stderr @@ -1,10 +1,12 @@ -error: missing `fn`, `type`, or `static` for extern-item declaration - --> $DIR/extern-no-fn.rs:1:9 +error: expected one of `!` or `::`, found `(` + --> $DIR/extern-no-fn.rs:2:6 | -LL | extern { - | _________^ -LL | | f(); - | |____^ missing `fn`, `type`, or `static` +LL | extern { + | - while parsing this item list starting here +LL | f(); + | ^ expected one of `!` or `::` +LL | } + | - the item list ends here error: aborting due to previous error diff --git a/src/test/ui/parser/fn-body-eq-expr-semi.rs b/src/test/ui/parser/fn-body-eq-expr-semi.rs new file mode 100644 index 00000000000..09444079365 --- /dev/null +++ b/src/test/ui/parser/fn-body-eq-expr-semi.rs @@ -0,0 +1,23 @@ +fn main() {} + +fn syntax() { + fn foo() = 42; //~ ERROR function body cannot be `= expression;` + fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;` +} + +extern { + fn foo() = 42; //~ ERROR function body cannot be `= expression;` + //~^ ERROR incorrect function inside `extern` block + fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;` + //~^ ERROR incorrect function inside `extern` block +} + +trait Foo { + fn foo() = 42; //~ ERROR function body cannot be `= expression;` + fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;` +} + +impl Foo for () { + fn foo() = 42; //~ ERROR function body cannot be `= expression;` + fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;` +} diff --git a/src/test/ui/parser/fn-body-eq-expr-semi.stderr b/src/test/ui/parser/fn-body-eq-expr-semi.stderr new file mode 100644 index 00000000000..739133e0b40 --- /dev/null +++ b/src/test/ui/parser/fn-body-eq-expr-semi.stderr @@ -0,0 +1,117 @@ +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:4:14 + | +LL | fn foo() = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn foo() { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:5:20 + | +LL | fn bar() -> u8 = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn bar() -> u8 { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:9:14 + | +LL | fn foo() = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn foo() { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:11:20 + | +LL | fn bar() -> u8 = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn bar() -> u8 { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:16:14 + | +LL | fn foo() = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn foo() { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:17:20 + | +LL | fn bar() -> u8 = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn bar() -> u8 { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:21:14 + | +LL | fn foo() = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn foo() { 42 } + | ^ ^ + +error: function body cannot be `= expression;` + --> $DIR/fn-body-eq-expr-semi.rs:22:20 + | +LL | fn bar() -> u8 = 42; + | ^^^^^ + | +help: surround the expression with `{` and `}` instead of `=` and `;` + | +LL | fn bar() -> u8 { 42 } + | ^ ^ + +error: incorrect function inside `extern` block + --> $DIR/fn-body-eq-expr-semi.rs:9:8 + | +LL | extern { + | ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body +LL | fn foo() = 42; + | ^^^ ----- help: remove the invalid body: `;` + | | + | cannot have a body + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: incorrect function inside `extern` block + --> $DIR/fn-body-eq-expr-semi.rs:11:8 + | +LL | extern { + | ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body +... +LL | fn bar() -> u8 = 42; + | ^^^ ----- help: remove the invalid body: `;` + | | + | cannot have a body + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr index 1142cee9851..d6b36fbb714 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.stderr +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -2,7 +2,7 @@ error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:13:5 | LL | const async unsafe extern "C" fn ff5() {} // OK. - | -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-^^^^^------------------------------ | | | | | `async` because of this | `const` because of this @@ -45,7 +45,7 @@ error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:21:9 | LL | const async unsafe extern "C" fn ft5(); - | -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-^^^^^---------------------------- | | | | | `async` because of this | `const` because of this @@ -88,7 +88,7 @@ error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:34:9 | LL | const async unsafe extern "C" fn ft5() {} - | -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-^^^^^------------------------------ | | | | | `async` because of this | `const` because of this @@ -97,7 +97,7 @@ error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:46:9 | LL | const async unsafe extern "C" fn fi5() {} - | -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-^^^^^------------------------------ | | | | | `async` because of this | `const` because of this @@ -160,7 +160,7 @@ error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:55:9 | LL | const async unsafe extern "C" fn fe5(); - | -----^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^-^^^^^---------------------------- | | | | | `async` because of this | `const` because of this diff --git a/src/test/ui/parser/foreign-const-semantic-fail.rs b/src/test/ui/parser/foreign-const-semantic-fail.rs new file mode 100644 index 00000000000..82978e655ba --- /dev/null +++ b/src/test/ui/parser/foreign-const-semantic-fail.rs @@ -0,0 +1,9 @@ +fn main() {} + +extern { + const A: isize; + //~^ ERROR extern items cannot be `const` + const B: isize = 42; + //~^ ERROR extern items cannot be `const` + //~| ERROR incorrect `static` inside `extern` block +} diff --git a/src/test/ui/parser/foreign-const-semantic-fail.stderr b/src/test/ui/parser/foreign-const-semantic-fail.stderr new file mode 100644 index 00000000000..f529b3ad87b --- /dev/null +++ b/src/test/ui/parser/foreign-const-semantic-fail.stderr @@ -0,0 +1,35 @@ +error: extern items cannot be `const` + --> $DIR/foreign-const-semantic-fail.rs:4:11 + | +LL | const A: isize; + | ------^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: extern items cannot be `const` + --> $DIR/foreign-const-semantic-fail.rs:6:11 + | +LL | const B: isize = 42; + | ------^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: incorrect `static` inside `extern` block + --> $DIR/foreign-const-semantic-fail.rs:6:11 + | +LL | extern { + | ------ `extern` blocks define existing foreign statics and statics inside of them cannot have a body +... +LL | const B: isize = 42; + | ^ -- the invalid body + | | + | cannot have a body + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/foreign-const-syntactic-fail.rs b/src/test/ui/parser/foreign-const-syntactic-fail.rs new file mode 100644 index 00000000000..a78f8b1623a --- /dev/null +++ b/src/test/ui/parser/foreign-const-syntactic-fail.rs @@ -0,0 +1,9 @@ +// Syntactically, a `const` item inside an `extern { ... }` block is not allowed. + +fn main() {} + +#[cfg(FALSE)] +extern { + const A: isize; //~ ERROR extern items cannot be `const` + const B: isize = 42; //~ ERROR extern items cannot be `const` +} diff --git a/src/test/ui/parser/foreign-const-syntactic-fail.stderr b/src/test/ui/parser/foreign-const-syntactic-fail.stderr new file mode 100644 index 00000000000..9cf58fa95fb --- /dev/null +++ b/src/test/ui/parser/foreign-const-syntactic-fail.stderr @@ -0,0 +1,22 @@ +error: extern items cannot be `const` + --> $DIR/foreign-const-syntactic-fail.rs:7:11 + | +LL | const A: isize; + | ------^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: extern items cannot be `const` + --> $DIR/foreign-const-syntactic-fail.rs:8:11 + | +LL | const B: isize = 42; + | ------^ + | | + | help: try using a static value: `static` + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/foreign-static-semantic-fail.rs b/src/test/ui/parser/foreign-static-semantic-fail.rs new file mode 100644 index 00000000000..9abdf33df9c --- /dev/null +++ b/src/test/ui/parser/foreign-static-semantic-fail.rs @@ -0,0 +1,8 @@ +// Syntactically, a foreign static may not have a body. + +fn main() {} + +extern { + static X: u8 = 0; //~ ERROR incorrect `static` inside `extern` block + static mut Y: u8 = 0; //~ ERROR incorrect `static` inside `extern` block +} diff --git a/src/test/ui/parser/foreign-static-semantic-fail.stderr b/src/test/ui/parser/foreign-static-semantic-fail.stderr new file mode 100644 index 00000000000..5942e3a9449 --- /dev/null +++ b/src/test/ui/parser/foreign-static-semantic-fail.stderr @@ -0,0 +1,27 @@ +error: incorrect `static` inside `extern` block + --> $DIR/foreign-static-semantic-fail.rs:6:12 + | +LL | extern { + | ------ `extern` blocks define existing foreign statics and statics inside of them cannot have a body +LL | static X: u8 = 0; + | ^ - the invalid body + | | + | cannot have a body + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: incorrect `static` inside `extern` block + --> $DIR/foreign-static-semantic-fail.rs:7:16 + | +LL | extern { + | ------ `extern` blocks define existing foreign statics and statics inside of them cannot have a body +LL | static X: u8 = 0; +LL | static mut Y: u8 = 0; + | ^ - the invalid body + | | + | cannot have a body + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/foreign-static-syntactic-pass.rs b/src/test/ui/parser/foreign-static-syntactic-pass.rs new file mode 100644 index 00000000000..2c805e8a0b7 --- /dev/null +++ b/src/test/ui/parser/foreign-static-syntactic-pass.rs @@ -0,0 +1,11 @@ +// Syntactically, a foreign static may have a body. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +extern { + static X: u8 = 0; + static mut Y: u8 = 0; +} diff --git a/src/test/ui/parser/foreign-ty-semantic-fail.rs b/src/test/ui/parser/foreign-ty-semantic-fail.rs new file mode 100644 index 00000000000..96b15232b10 --- /dev/null +++ b/src/test/ui/parser/foreign-ty-semantic-fail.rs @@ -0,0 +1,18 @@ +#![feature(extern_types)] + +fn main() {} + +extern "C" { + type A: Ord; + //~^ ERROR bounds on `type`s in `extern` blocks have no effect + type B<'a> where 'a: 'static; + //~^ ERROR `type`s inside `extern` blocks cannot have generic parameters + //~| ERROR `type`s inside `extern` blocks cannot have `where` clauses + type C where T: 'static; + //~^ ERROR `type`s inside `extern` blocks cannot have generic parameters + //~| ERROR `type`s inside `extern` blocks cannot have `where` clauses + type D = u8; + //~^ ERROR incorrect `type` inside `extern` block + + type E: where; +} diff --git a/src/test/ui/parser/foreign-ty-semantic-fail.stderr b/src/test/ui/parser/foreign-ty-semantic-fail.stderr new file mode 100644 index 00000000000..588e4966aae --- /dev/null +++ b/src/test/ui/parser/foreign-ty-semantic-fail.stderr @@ -0,0 +1,65 @@ +error: bounds on `type`s in `extern` blocks have no effect + --> $DIR/foreign-ty-semantic-fail.rs:6:13 + | +LL | type A: Ord; + | ^^^ + +error: `type`s inside `extern` blocks cannot have generic parameters + --> $DIR/foreign-ty-semantic-fail.rs:8:11 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type B<'a> where 'a: 'static; + | ^^^^ help: remove the generic parameters + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: `type`s inside `extern` blocks cannot have `where` clauses + --> $DIR/foreign-ty-semantic-fail.rs:8:16 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type B<'a> where 'a: 'static; + | ^^^^^^^^^^^^^^^^^ help: remove the `where` clause + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: `type`s inside `extern` blocks cannot have generic parameters + --> $DIR/foreign-ty-semantic-fail.rs:11:11 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type C where T: 'static; + | ^^^^^^^^ help: remove the generic parameters + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: `type`s inside `extern` blocks cannot have `where` clauses + --> $DIR/foreign-ty-semantic-fail.rs:11:20 + | +LL | extern "C" { + | ---------- `extern` block begins here +... +LL | type C where T: 'static; + | ^^^^^^^^^^^^^^^^ help: remove the `where` clause + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: incorrect `type` inside `extern` block + --> $DIR/foreign-ty-semantic-fail.rs:14:10 + | +LL | extern "C" { + | ---------- `extern` blocks define existing foreign types and types inside of them cannot have a body +... +LL | type D = u8; + | ^ -- the invalid body + | | + | cannot have a body + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/parser/foreign-ty-syntactic-pass.rs b/src/test/ui/parser/foreign-ty-syntactic-pass.rs new file mode 100644 index 00000000000..a746de1f14f --- /dev/null +++ b/src/test/ui/parser/foreign-ty-syntactic-pass.rs @@ -0,0 +1,12 @@ +// check-pass + +fn main() {} + +#[cfg(FALSE)] +extern "C" { + type A: Ord; + type A<'a> where 'a: 'static; + type A where T: 'static; + type A = u8; + type A<'a: 'static, T: Ord + 'static>: Eq + PartialEq where T: 'static + Copy = Vec; +} diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs index 9c321c4bd0d..fa9c7ababcf 100644 --- a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs +++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs @@ -11,11 +11,11 @@ impl X { //~| ERROR associated types are not yet supported in inherent impls type Z: Ord; //~^ ERROR associated type in `impl` without body - //~| ERROR bounds on associated `type`s in `impl`s have no effect + //~| ERROR bounds on `type`s in `impl`s have no effect //~| ERROR associated types are not yet supported in inherent impls type W: Ord where Self: Eq; //~^ ERROR associated type in `impl` without body - //~| ERROR bounds on associated `type`s in `impl`s have no effect + //~| ERROR bounds on `type`s in `impl`s have no effect //~| ERROR associated types are not yet supported in inherent impls type W where Self: Eq; //~^ ERROR associated type in `impl` without body diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr index 65e1981e3ac..541d9317c79 100644 --- a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr +++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr @@ -14,7 +14,7 @@ LL | type Z: Ord; | | | help: provide a definition for the type: `= ;` -error: bounds on associated `type`s in `impl`s have no effect +error: bounds on `type`s in `impl`s have no effect --> $DIR/impl-item-type-no-body-semantic-fail.rs:12:13 | LL | type Z: Ord; @@ -28,7 +28,7 @@ LL | type W: Ord where Self: Eq; | | | help: provide a definition for the type: `= ;` -error: bounds on associated `type`s in `impl`s have no effect +error: bounds on `type`s in `impl`s have no effect --> $DIR/impl-item-type-no-body-semantic-fail.rs:16:13 | LL | type W: Ord where Self: Eq; diff --git a/src/test/ui/parser/impl-parsing.rs b/src/test/ui/parser/impl-parsing.rs index 270c8b43dfd..80ce8885570 100644 --- a/src/test/ui/parser/impl-parsing.rs +++ b/src/test/ui/parser/impl-parsing.rs @@ -6,4 +6,5 @@ impl Trait .. {} //~ ERROR missing `for` in a trait impl impl ?Sized for Type {} //~ ERROR expected a trait, found type impl ?Sized for .. {} //~ ERROR expected a trait, found type -default unsafe FAIL //~ ERROR expected `impl`, found `FAIL` +default unsafe FAIL //~ ERROR expected item, found keyword `unsafe` +//~^ ERROR `default` is not followed by an item diff --git a/src/test/ui/parser/impl-parsing.stderr b/src/test/ui/parser/impl-parsing.stderr index 7c2a7937c5d..755addf1452 100644 --- a/src/test/ui/parser/impl-parsing.stderr +++ b/src/test/ui/parser/impl-parsing.stderr @@ -22,11 +22,19 @@ error: expected a trait, found type LL | impl ?Sized for .. {} | ^^^^^^ -error: expected `impl`, found `FAIL` - --> $DIR/impl-parsing.rs:9:16 +error: `default` is not followed by an item + --> $DIR/impl-parsing.rs:9:1 | LL | default unsafe FAIL - | ^^^^ expected `impl` + | ^^^^^^^ the `default` qualifier + | + = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` + +error: expected item, found keyword `unsafe` + --> $DIR/impl-parsing.rs:9:9 + | +LL | default unsafe FAIL + | ^^^^^^ expected item -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/inner-attr-after-doc-comment.stderr b/src/test/ui/parser/inner-attr-after-doc-comment.stderr index b012abc25e7..c1e9e7a427f 100644 --- a/src/test/ui/parser/inner-attr-after-doc-comment.stderr +++ b/src/test/ui/parser/inner-attr-after-doc-comment.stderr @@ -7,7 +7,7 @@ LL | | */ | |___- previous doc comment LL | LL | #![recursion_limit="100"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attibute + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attribute | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. diff --git a/src/test/ui/parser/inner-attr-in-trait-def.rs b/src/test/ui/parser/inner-attr-in-trait-def.rs new file mode 100644 index 00000000000..8dba6b362cd --- /dev/null +++ b/src/test/ui/parser/inner-attr-in-trait-def.rs @@ -0,0 +1,9 @@ +// check-pass + +#![deny(non_camel_case_types)] + +fn main() {} + +trait foo_bar { + #![allow(non_camel_case_types)] +} diff --git a/src/test/ui/parser/inner-attr.stderr b/src/test/ui/parser/inner-attr.stderr index 070d9f47d96..e1bf2cca1c9 100644 --- a/src/test/ui/parser/inner-attr.stderr +++ b/src/test/ui/parser/inner-attr.stderr @@ -5,7 +5,7 @@ LL | #[feature(lang_items)] | ---------------------- previous outer attribute LL | LL | #![recursion_limit="100"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attibute + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attribute | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them. diff --git a/src/test/ui/parser/issue-14303-fncall.rs b/src/test/ui/parser/issue-14303-fncall.rs index 39694198cdb..46ece84d69e 100644 --- a/src/test/ui/parser/issue-14303-fncall.rs +++ b/src/test/ui/parser/issue-14303-fncall.rs @@ -11,7 +11,7 @@ fn foo<'a, 'b>(start: &'a usize, end: &'a usize) { let _x = (*start..*end) .map(|x| S { a: start, b: end }) .collect::>>(); - //~^ ERROR lifetime arguments must be declared prior to type arguments + //~^ ERROR type provided when a lifetime was expected } fn main() {} diff --git a/src/test/ui/parser/issue-14303-fncall.stderr b/src/test/ui/parser/issue-14303-fncall.stderr index 8ef9f1a1a6c..10954223713 100644 --- a/src/test/ui/parser/issue-14303-fncall.stderr +++ b/src/test/ui/parser/issue-14303-fncall.stderr @@ -1,8 +1,11 @@ -error: lifetime arguments must be declared prior to type arguments - --> $DIR/issue-14303-fncall.rs:13:29 +error[E0747]: type provided when a lifetime was expected + --> $DIR/issue-14303-fncall.rs:13:26 | LL | .collect::>>(); - | ^^ + | ^ + | + = note: lifetime arguments must be provided before type arguments error: aborting due to previous error +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/parser/issue-14303-path.rs b/src/test/ui/parser/issue-14303-path.rs index 386d19859e4..89ef914aba2 100644 --- a/src/test/ui/parser/issue-14303-path.rs +++ b/src/test/ui/parser/issue-14303-path.rs @@ -8,6 +8,6 @@ mod foo { } fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {} -//~^ ERROR lifetime arguments must be declared prior to type arguments +//~^ ERROR type provided when a lifetime was expected fn main() {} diff --git a/src/test/ui/parser/issue-14303-path.stderr b/src/test/ui/parser/issue-14303-path.stderr index 19f2995ebee..c1ad2332b5b 100644 --- a/src/test/ui/parser/issue-14303-path.stderr +++ b/src/test/ui/parser/issue-14303-path.stderr @@ -1,8 +1,11 @@ -error: lifetime arguments must be declared prior to type arguments - --> $DIR/issue-14303-path.rs:10:40 +error[E0747]: type provided when a lifetime was expected + --> $DIR/issue-14303-path.rs:10:37 | LL | fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {} - | ^^ ^^ + | ^ + | + = note: lifetime arguments must be provided before type arguments error: aborting due to previous error +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/parser/issue-1655.rs b/src/test/ui/parser/issue-1655.rs index 3d0bf3c1c7b..e9fc6f15346 100644 --- a/src/test/ui/parser/issue-1655.rs +++ b/src/test/ui/parser/issue-1655.rs @@ -1,6 +1,5 @@ -// error-pattern:expected `[`, found `vec` mod blade_runner { - #vec[doc( + #vec[doc( //~ ERROR expected one of `!` or `[`, found `vec` brief = "Blade Runner is probably the best movie ever", desc = "I like that in the world of Blade Runner it is always raining, and that it's always night time. And Aliens diff --git a/src/test/ui/parser/issue-1655.stderr b/src/test/ui/parser/issue-1655.stderr index 3f656b63cdb..0c390a0ec56 100644 --- a/src/test/ui/parser/issue-1655.stderr +++ b/src/test/ui/parser/issue-1655.stderr @@ -1,8 +1,8 @@ -error: expected `[`, found `vec` - --> $DIR/issue-1655.rs:3:6 +error: expected one of `!` or `[`, found `vec` + --> $DIR/issue-1655.rs:2:6 | LL | #vec[doc( - | ^^^ expected `[` + | ^^^ expected one of `!` or `[` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-19398.rs b/src/test/ui/parser/issue-19398.rs index 2158a2fd6c1..46eb320a172 100644 --- a/src/test/ui/parser/issue-19398.rs +++ b/src/test/ui/parser/issue-19398.rs @@ -1,5 +1,6 @@ trait T { - extern "Rust" unsafe fn foo(); //~ ERROR expected one of `async`, `const` + extern "Rust" unsafe fn foo(); + //~^ ERROR expected `{`, found keyword `unsafe` } fn main() {} diff --git a/src/test/ui/parser/issue-19398.stderr b/src/test/ui/parser/issue-19398.stderr index 201a6b2d66a..1da00960adf 100644 --- a/src/test/ui/parser/issue-19398.stderr +++ b/src/test/ui/parser/issue-19398.stderr @@ -1,10 +1,13 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `extern` - --> $DIR/issue-19398.rs:2:5 +error: expected `{`, found keyword `unsafe` + --> $DIR/issue-19398.rs:2:19 | LL | trait T { - | - expected one of 10 possible tokens + | - while parsing this item list starting here LL | extern "Rust" unsafe fn foo(); - | ^^^^^^ unexpected token + | ^^^^^^ expected `{` +LL | +LL | } + | - the item list ends here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-20711-2.rs b/src/test/ui/parser/issue-20711-2.rs index 0063a334182..168c7e76162 100644 --- a/src/test/ui/parser/issue-20711-2.rs +++ b/src/test/ui/parser/issue-20711-2.rs @@ -4,6 +4,7 @@ impl Foo { fn foo() {} #[stable(feature = "rust1", since = "1.0.0")] -} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or + //~^ ERROR expected item after attributes +} fn main() {} diff --git a/src/test/ui/parser/issue-20711-2.stderr b/src/test/ui/parser/issue-20711-2.stderr index ee484890fad..12b18bbc594 100644 --- a/src/test/ui/parser/issue-20711-2.stderr +++ b/src/test/ui/parser/issue-20711-2.stderr @@ -1,10 +1,14 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}` - --> $DIR/issue-20711-2.rs:7:1 +error: expected item after attributes + --> $DIR/issue-20711-2.rs:6:5 | +LL | impl Foo { + | - while parsing this item list starting here +... LL | #[stable(feature = "rust1", since = "1.0.0")] - | - expected one of 9 possible tokens + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | } - | ^ unexpected token + | - the item list ends here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-20711.rs b/src/test/ui/parser/issue-20711.rs index dc216167b8a..020bb79d6e7 100644 --- a/src/test/ui/parser/issue-20711.rs +++ b/src/test/ui/parser/issue-20711.rs @@ -2,6 +2,7 @@ struct Foo; impl Foo { #[stable(feature = "rust1", since = "1.0.0")] -} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or + //~^ ERROR expected item after attributes +} fn main() {} diff --git a/src/test/ui/parser/issue-20711.stderr b/src/test/ui/parser/issue-20711.stderr index 152c9f1c689..4af4b22bee2 100644 --- a/src/test/ui/parser/issue-20711.stderr +++ b/src/test/ui/parser/issue-20711.stderr @@ -1,10 +1,13 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}` - --> $DIR/issue-20711.rs:5:1 +error: expected item after attributes + --> $DIR/issue-20711.rs:4:5 | +LL | impl Foo { + | - while parsing this item list starting here LL | #[stable(feature = "rust1", since = "1.0.0")] - | - expected one of 9 possible tokens + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | } - | ^ unexpected token + | - the item list ends here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-21153.rs b/src/test/ui/parser/issue-21153.rs index 46cd45f28b4..bf5fdb1f3c6 100644 --- a/src/test/ui/parser/issue-21153.rs +++ b/src/test/ui/parser/issue-21153.rs @@ -1,5 +1,6 @@ -trait MyTrait: Iterator { //~ ERROR missing `fn`, `type`, or `const` +trait MyTrait: Iterator { Item = T; + //~^ ERROR expected one of `!` or `::`, found `=` } fn main() {} diff --git a/src/test/ui/parser/issue-21153.stderr b/src/test/ui/parser/issue-21153.stderr index 6e20a9ce3c4..cbfa9ded3c3 100644 --- a/src/test/ui/parser/issue-21153.stderr +++ b/src/test/ui/parser/issue-21153.stderr @@ -1,10 +1,13 @@ -error: missing `fn`, `type`, or `const` for associated-item declaration - --> $DIR/issue-21153.rs:1:29 +error: expected one of `!` or `::`, found `=` + --> $DIR/issue-21153.rs:2:10 | -LL | trait MyTrait: Iterator { - | _____________________________^ -LL | | Item = T; - | |____^ missing `fn`, `type`, or `const` +LL | trait MyTrait: Iterator { + | - while parsing this item list starting here +LL | Item = T; + | ^ expected one of `!` or `::` +LL | +LL | } + | - the item list ends here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-32446.stderr b/src/test/ui/parser/issue-32446.stderr index 1a97f54160b..7515369aaa0 100644 --- a/src/test/ui/parser/issue-32446.stderr +++ b/src/test/ui/parser/issue-32446.stderr @@ -1,8 +1,11 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `...` +error: non-item in item list --> $DIR/issue-32446.rs:4:11 | LL | trait T { ... } - | ^^^ expected one of 10 possible tokens + | - ^^^ - item list ends here + | | | + | | non-item starts here + | item list starts here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.rs b/src/test/ui/parser/issue-35813-postfix-after-cast.rs new file mode 100644 index 00000000000..e725aa5d73d --- /dev/null +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.rs @@ -0,0 +1,171 @@ +// edition:2018 +#![crate_type = "lib"] +#![feature(type_ascription)] +use std::future::Future; +use std::pin::Pin; + +// This tests the parser for "x as Y[z]". It errors, but we want to give useful +// errors and parse such that further code gives useful errors. +pub fn index_after_as_cast() { + vec![1, 2, 3] as Vec[0]; + //~^ ERROR: casts cannot be followed by indexing + vec![1, 2, 3]: Vec[0]; + //~^ ERROR: casts cannot be followed by indexing +} + +pub fn index_after_cast_to_index() { + (&[0]) as &[i32][0]; + //~^ ERROR: casts cannot be followed by indexing + (&[0i32]): &[i32; 1][0]; + //~^ ERROR: casts cannot be followed by indexing +} + +pub fn cast_after_cast() { + if 5u64 as i32 as u16 == 0u16 { + + } + if 5u64: u64: u64 == 0u64 { + + } + let _ = 5u64: u64: u64 as u8 as i8 == 9i8; + let _ = 0i32: i32: i32; + let _ = 0 as i32: i32; + let _ = 0i32: i32 as i32; + let _ = 0 as i32 as i32; + let _ = 0i32: i32: i32 as u32 as i32; +} + +pub fn cast_cast_method_call() { + let _ = 0i32: i32: i32.count_ones(); + //~^ ERROR: casts cannot be followed by a method call + let _ = 0 as i32: i32.count_ones(); + //~^ ERROR: casts cannot be followed by a method call + let _ = 0i32: i32 as i32.count_ones(); + //~^ ERROR: casts cannot be followed by a method call + let _ = 0 as i32 as i32.count_ones(); + //~^ ERROR: casts cannot be followed by a method call + let _ = 0i32: i32: i32 as u32 as i32.count_ones(); + //~^ ERROR: casts cannot be followed by a method call + let _ = 0i32: i32.count_ones(): u32; + //~^ ERROR: casts cannot be followed by a method call + let _ = 0 as i32.count_ones(): u32; + //~^ ERROR: casts cannot be followed by a method call + let _ = 0i32: i32.count_ones() as u32; + //~^ ERROR: casts cannot be followed by a method call + let _ = 0 as i32.count_ones() as u32; + //~^ ERROR: casts cannot be followed by a method call + let _ = 0i32: i32: i32.count_ones() as u32 as i32; + //~^ ERROR: casts cannot be followed by a method call +} + +pub fn multiline_error() { + let _ = 0 + as i32 + .count_ones(); + //~^^^ ERROR: casts cannot be followed by a method call +} + +// this tests that the precedence for `!x as Y.Z` is still what we expect +pub fn precedence() { + let x: i32 = &vec![1, 2, 3] as &Vec[0]; + //~^ ERROR: casts cannot be followed by indexing +} + +pub fn method_calls() { + 0 as i32.max(0); + //~^ ERROR: casts cannot be followed by a method call + 0: i32.max(0); + //~^ ERROR: casts cannot be followed by a method call +} + +pub fn complex() { + let _ = format!( + "{} and {}", + if true { 33 } else { 44 } as i32.max(0), + //~^ ERROR: casts cannot be followed by a method call + if true { 33 } else { 44 }: i32.max(0) + //~^ ERROR: casts cannot be followed by a method call + ); +} + +pub fn in_condition() { + if 5u64 as i32.max(0) == 0 { + //~^ ERROR: casts cannot be followed by a method call + } + if 5u64: u64.max(0) == 0 { + //~^ ERROR: casts cannot be followed by a method call + } +} + +pub fn inside_block() { + let _ = if true { + 5u64 as u32.max(0) == 0 + //~^ ERROR: casts cannot be followed by a method call + } else { false }; + let _ = if true { + 5u64: u64.max(0) == 0 + //~^ ERROR: casts cannot be followed by a method call + } else { false }; +} + +static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); +//~^ ERROR: casts cannot be followed by indexing + +static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); +//~^ ERROR: casts cannot be followed by indexing + + +pub fn cast_then_try() -> Result { + Err(0u64) as Result?; + //~^ ERROR: casts cannot be followed by ? + Err(0u64): Result?; + //~^ ERROR: casts cannot be followed by ? + Ok(1) +} + + +pub fn cast_then_call() { + type F = fn(u8); + // type ascription won't actually do [unique drop fn type] -> fn(u8) casts. + let drop_ptr = drop as fn(u8); + drop as F(); + //~^ ERROR: parenthesized type parameters may only be used with a `Fn` trait [E0214] + drop_ptr: F(); + //~^ ERROR: parenthesized type parameters may only be used with a `Fn` trait [E0214] +} + +pub fn cast_to_fn_should_work() { + let drop_ptr = drop as fn(u8); + drop as fn(u8); + drop_ptr: fn(u8); +} + +pub fn parens_after_cast_error() { + let drop_ptr = drop as fn(u8); + drop as fn(u8)(0); + //~^ ERROR: casts cannot be followed by a function call + drop_ptr: fn(u8)(0); + //~^ ERROR: casts cannot be followed by a function call +} + +pub async fn cast_then_await() { + Box::pin(noop()) as Pin>>.await; + //~^ ERROR: casts cannot be followed by `.await` + + Box::pin(noop()): Pin>.await; + //~^ ERROR: casts cannot be followed by `.await` +} + +pub async fn noop() {} + +#[derive(Default)] +pub struct Foo { + pub bar: u32, +} + +pub fn struct_field() { + Foo::default() as Foo.bar; + //~^ ERROR: cannot be followed by a field access + Foo::default(): Foo.bar; + //~^ ERROR: cannot be followed by a field access +} diff --git a/src/test/ui/parser/issue-35813-postfix-after-cast.stderr b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr new file mode 100644 index 00000000000..255e9f40921 --- /dev/null +++ b/src/test/ui/parser/issue-35813-postfix-after-cast.stderr @@ -0,0 +1,392 @@ +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:10:5 + | +LL | vec![1, 2, 3] as Vec[0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (vec![1, 2, 3] as Vec)[0]; + | ^ ^ + +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:12:5 + | +LL | vec![1, 2, 3]: Vec[0]; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (vec![1, 2, 3]: Vec)[0]; + | ^ ^ + +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:17:5 + | +LL | (&[0]) as &[i32][0]; + | ^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | ((&[0]) as &[i32])[0]; + | ^ ^ + +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:19:5 + | +LL | (&[0i32]): &[i32; 1][0]; + | ^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | ((&[0i32]): &[i32; 1])[0]; + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:39:13 + | +LL | let _ = 0i32: i32: i32.count_ones(); + | ^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32: i32).count_ones(); + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:41:13 + | +LL | let _ = 0 as i32: i32.count_ones(); + | ^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0 as i32: i32).count_ones(); + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:43:13 + | +LL | let _ = 0i32: i32 as i32.count_ones(); + | ^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32 as i32).count_ones(); + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:45:13 + | +LL | let _ = 0 as i32 as i32.count_ones(); + | ^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0 as i32 as i32).count_ones(); + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:47:13 + | +LL | let _ = 0i32: i32: i32 as u32 as i32.count_ones(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32: i32 as u32 as i32).count_ones(); + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:49:13 + | +LL | let _ = 0i32: i32.count_ones(): u32; + | ^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32).count_ones(): u32; + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:51:13 + | +LL | let _ = 0 as i32.count_ones(): u32; + | ^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0 as i32).count_ones(): u32; + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:53:13 + | +LL | let _ = 0i32: i32.count_ones() as u32; + | ^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32).count_ones() as u32; + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:55:13 + | +LL | let _ = 0 as i32.count_ones() as u32; + | ^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0 as i32).count_ones() as u32; + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:57:13 + | +LL | let _ = 0i32: i32: i32.count_ones() as u32 as i32; + | ^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0i32: i32: i32).count_ones() as u32 as i32; + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:62:13 + | +LL | let _ = 0 + | _____________^ +LL | | as i32 + | |______________^ + | +help: try surrounding the expression in parentheses + | +LL | let _ = (0 +LL | as i32) + | + +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:70:18 + | +LL | let x: i32 = &vec![1, 2, 3] as &Vec[0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | let x: i32 = (&vec![1, 2, 3] as &Vec)[0]; + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:75:5 + | +LL | 0 as i32.max(0); + | ^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (0 as i32).max(0); + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:77:5 + | +LL | 0: i32.max(0); + | ^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (0: i32).max(0); + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:92:8 + | +LL | if 5u64 as i32.max(0) == 0 { + | ^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | if (5u64 as i32).max(0) == 0 { + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:95:8 + | +LL | if 5u64: u64.max(0) == 0 { + | ^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | if (5u64: u64).max(0) == 0 { + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:102:9 + | +LL | 5u64 as u32.max(0) == 0 + | ^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (5u64 as u32).max(0) == 0 + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:106:9 + | +LL | 5u64: u64.max(0) == 0 + | ^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (5u64: u64).max(0) == 0 + | ^ ^ + +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:111:24 + | +LL | static bar: &[i32] = &(&[1,2,3] as &[i32][0..1]); + | ^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | static bar: &[i32] = &((&[1,2,3] as &[i32])[0..1]); + | ^ ^ + +error: casts cannot be followed by indexing + --> $DIR/issue-35813-postfix-after-cast.rs:114:25 + | +LL | static bar2: &[i32] = &(&[1i32,2,3]: &[i32; 3][0..1]); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | static bar2: &[i32] = &((&[1i32,2,3]: &[i32; 3])[0..1]); + | ^ ^ + +error: casts cannot be followed by ? + --> $DIR/issue-35813-postfix-after-cast.rs:119:5 + | +LL | Err(0u64) as Result?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (Err(0u64) as Result)?; + | ^ ^ + +error: casts cannot be followed by ? + --> $DIR/issue-35813-postfix-after-cast.rs:121:5 + | +LL | Err(0u64): Result?; + | ^^^^^^^^^-^^^^^^^^^^^^^^^^ + | | + | help: maybe write a path separator here: `::` + | + = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` + = note: see issue #23416 for more information + +error: casts cannot be followed by a function call + --> $DIR/issue-35813-postfix-after-cast.rs:145:5 + | +LL | drop as fn(u8)(0); + | ^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (drop as fn(u8))(0); + | ^ ^ + +error: casts cannot be followed by a function call + --> $DIR/issue-35813-postfix-after-cast.rs:147:5 + | +LL | drop_ptr: fn(u8)(0); + | ^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (drop_ptr: fn(u8))(0); + | ^ ^ + +error: casts cannot be followed by `.await` + --> $DIR/issue-35813-postfix-after-cast.rs:152:5 + | +LL | Box::pin(noop()) as Pin>>.await; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (Box::pin(noop()) as Pin>>).await; + | ^ ^ + +error: casts cannot be followed by `.await` + --> $DIR/issue-35813-postfix-after-cast.rs:155:5 + | +LL | Box::pin(noop()): Pin>.await; + | ^^^^^^^^^^^^^^^^-^^^^^^^^^^^^ + | | + | help: maybe write a path separator here: `::` + | + = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` + = note: see issue #23416 for more information + +error: casts cannot be followed by a field access + --> $DIR/issue-35813-postfix-after-cast.rs:167:5 + | +LL | Foo::default() as Foo.bar; + | ^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (Foo::default() as Foo).bar; + | ^ ^ + +error: casts cannot be followed by a field access + --> $DIR/issue-35813-postfix-after-cast.rs:169:5 + | +LL | Foo::default(): Foo.bar; + | ^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (Foo::default(): Foo).bar; + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:84:9 + | +LL | if true { 33 } else { 44 } as i32.max(0), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (if true { 33 } else { 44 } as i32).max(0), + | ^ ^ + +error: casts cannot be followed by a method call + --> $DIR/issue-35813-postfix-after-cast.rs:86:9 + | +LL | if true { 33 } else { 44 }: i32.max(0) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try surrounding the expression in parentheses + | +LL | (if true { 33 } else { 44 }: i32).max(0) + | ^ ^ + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/issue-35813-postfix-after-cast.rs:131:13 + | +LL | drop as F(); + | ^^^ only `Fn` traits may use parentheses + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/issue-35813-postfix-after-cast.rs:133:15 + | +LL | drop_ptr: F(); + | ^^^ only `Fn` traits may use parentheses + +error: aborting due to 36 previous errors + +For more information about this error, try `rustc --explain E0214`. diff --git a/src/test/ui/parser/issue-41155.rs b/src/test/ui/parser/issue-41155.rs index 3c24d2b447d..5a7488e6ffc 100644 --- a/src/test/ui/parser/issue-41155.rs +++ b/src/test/ui/parser/issue-41155.rs @@ -1,7 +1,7 @@ struct S; impl S { - pub -} //~ ERROR expected one of + pub //~ ERROR visibility `pub` is not followed by an item +} //~ ERROR non-item in item list fn main() {} diff --git a/src/test/ui/parser/issue-41155.stderr b/src/test/ui/parser/issue-41155.stderr index 0e191eb7e0a..8491afae230 100644 --- a/src/test/ui/parser/issue-41155.stderr +++ b/src/test/ui/parser/issue-41155.stderr @@ -1,10 +1,22 @@ -error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}` +error: visibility `pub` is not followed by an item + --> $DIR/issue-41155.rs:4:5 + | +LL | pub + | ^^^ the visibility + | + = help: you likely meant to define an item, e.g., `pub fn foo() {}` + +error: non-item in item list --> $DIR/issue-41155.rs:5:1 | +LL | impl S { + | - item list starts here LL | pub - | - expected one of 8 possible tokens LL | } - | ^ unexpected token + | ^ + | | + | non-item starts here + | item list ends here -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs b/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs new file mode 100644 index 00000000000..48a679b2d09 --- /dev/null +++ b/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs @@ -0,0 +1,44 @@ +fn main() {} + +macro_rules! expand_to_enum { + () => { + enum BadE {} + //~^ ERROR enum is not supported in `trait`s or `impl`s + //~| ERROR enum is not supported in `trait`s or `impl`s + //~| ERROR enum is not supported in `extern` blocks + }; +} + +macro_rules! mac_impl { + ($($i:item)*) => { + struct S; + impl S { $($i)* } + } +} + +mac_impl! { + struct BadS; //~ ERROR struct is not supported in `trait`s or `impl`s + expand_to_enum!(); +} + +macro_rules! mac_trait { + ($($i:item)*) => { + trait T { $($i)* } + } +} + +mac_trait! { + struct BadS; //~ ERROR struct is not supported in `trait`s or `impl`s + expand_to_enum!(); +} + +macro_rules! mac_extern { + ($($i:item)*) => { + extern "C" { $($i)* } + } +} + +mac_extern! { + struct BadS; //~ ERROR struct is not supported in `extern` blocks + expand_to_enum!(); +} diff --git a/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.stderr b/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.stderr new file mode 100644 index 00000000000..bfd27a1a41e --- /dev/null +++ b/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.stderr @@ -0,0 +1,53 @@ +error: struct is not supported in `trait`s or `impl`s + --> $DIR/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs:20:5 + | +LL | struct BadS; + | ^^^^^^^^^^^^ + +error: enum is not supported in `trait`s or `impl`s + --> $DIR/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs:5:9 + | +LL | enum BadE {} + | ^^^^^^^^^ +... +LL | expand_to_enum!(); + | ------------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: struct is not supported in `trait`s or `impl`s + --> $DIR/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs:31:5 + | +LL | struct BadS; + | ^^^^^^^^^^^^ + +error: enum is not supported in `trait`s or `impl`s + --> $DIR/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs:5:9 + | +LL | enum BadE {} + | ^^^^^^^^^ +... +LL | expand_to_enum!(); + | ------------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: struct is not supported in `extern` blocks + --> $DIR/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs:42:5 + | +LL | struct BadS; + | ^^^^^^^^^^^^ + +error: enum is not supported in `extern` blocks + --> $DIR/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs:5:9 + | +LL | enum BadE {} + | ^^^^^^^^^ +... +LL | expand_to_enum!(); + | ------------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items.rs b/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items.rs new file mode 100644 index 00000000000..8592f8a7287 --- /dev/null +++ b/src/test/ui/parser/issue-48137-macros-cannot-interpolate-impl-items.rs @@ -0,0 +1,34 @@ +// check-pass + +fn main() {} + +macro_rules! mac_impl { + ($i:item) => { + struct S; + impl S { $i } + } +} + +mac_impl! { + fn foo() {} +} + +macro_rules! mac_trait { + ($i:item) => { + trait T { $i } + } +} + +mac_trait! { + fn foo() {} +} + +macro_rules! mac_extern { + ($i:item) => { + extern "C" { $i } + } +} + +mac_extern! { + fn foo(); +} diff --git a/src/test/ui/parser/issue-5806.stderr b/src/test/ui/parser/issue-5806.stderr index 6cf902ca86e..bdb5c91ff91 100644 --- a/src/test/ui/parser/issue-5806.stderr +++ b/src/test/ui/parser/issue-5806.stderr @@ -1,8 +1,8 @@ error: couldn't read $DIR/../parser: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) - --> $DIR/issue-5806.rs:5:5 + --> $DIR/issue-5806.rs:5:1 | LL | mod foo; - | ^^^ + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr b/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr index 00f6652b311..8a44ee761ed 100644 --- a/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr +++ b/src/test/ui/parser/issue-58094-missing-right-square-bracket.stderr @@ -7,10 +7,10 @@ LL | #[Ѕ | unclosed delimiter error: expected item after attributes - --> $DIR/issue-58094-missing-right-square-bracket.rs:4:4 + --> $DIR/issue-58094-missing-right-square-bracket.rs:4:1 | LL | #[Ѕ - | ^ + | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/issue-62894.rs b/src/test/ui/parser/issue-62894.rs new file mode 100644 index 00000000000..b9c0bf834dd --- /dev/null +++ b/src/test/ui/parser/issue-62894.rs @@ -0,0 +1,7 @@ +// Regression test for #62894, shouldn't crash. +// error-pattern: this file contains an unclosed delimiter +// error-pattern: expected one of `(`, `[`, or `{`, found keyword `fn` + +fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + +fn main() {} diff --git a/src/test/ui/parser/issue-62894.stderr b/src/test/ui/parser/issue-62894.stderr new file mode 100644 index 00000000000..6db380f7a7f --- /dev/null +++ b/src/test/ui/parser/issue-62894.stderr @@ -0,0 +1,47 @@ +error: this file contains an unclosed delimiter + --> $DIR/issue-62894.rs:7:14 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +LL | +LL | fn main() {} + | ^ + +error: this file contains an unclosed delimiter + --> $DIR/issue-62894.rs:7:14 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +LL | +LL | fn main() {} + | ^ + +error: this file contains an unclosed delimiter + --> $DIR/issue-62894.rs:7:14 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +LL | +LL | fn main() {} + | ^ + +error: expected one of `(`, `[`, or `{`, found keyword `fn` + --> $DIR/issue-62894.rs:7:1 + | +LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! + | - expected one of `(`, `[`, or `{` +LL | +LL | fn main() {} + | ^^ unexpected token + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/parser/issue-63116.stderr b/src/test/ui/parser/issue-63116.stderr index 2beb73d83d2..15cd3df860b 100644 --- a/src/test/ui/parser/issue-63116.stderr +++ b/src/test/ui/parser/issue-63116.stderr @@ -12,7 +12,7 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;` LL | impl W `, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, or lifetime, found `;` +error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;` --> $DIR/issue-63116.rs:3:15 | LL | impl W $DIR/issue-63135.rs:3:16 | LL | fn i(n{...,f # - | ^ expected `[` + | ^ expected one of `!` or `[` -error: expected one of `:` or `|`, found `)` - --> $DIR/issue-63135.rs:3:16 - | -LL | fn i(n{...,f # - | ^ expected one of `:` or `|` - -error: expected `;` or `{`, found `` - --> $DIR/issue-63135.rs:3:16 - | -LL | fn i(n{...,f # - | ^ expected `;` or `{` - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/issue-6610.stderr b/src/test/ui/parser/issue-6610.stderr index 22d93bffead..a9804208946 100644 --- a/src/test/ui/parser/issue-6610.stderr +++ b/src/test/ui/parser/issue-6610.stderr @@ -2,7 +2,11 @@ error: expected `;` or `{`, found `}` --> $DIR/issue-6610.rs:1:20 | LL | trait Foo { fn a() } - | ^ expected `;` or `{` + | - ^ + | | | + | | expected `;` or `{` + | | the item list ends here + | while parsing this item list starting here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-68730.rs b/src/test/ui/parser/issue-68730.rs index b570e941775..20e18b4bcbb 100644 Binary files a/src/test/ui/parser/issue-68730.rs and b/src/test/ui/parser/issue-68730.rs differ diff --git a/src/test/ui/parser/issue-68730.stderr b/src/test/ui/parser/issue-68730.stderr index 090b41d839f..9f8833e17fe 100644 Binary files a/src/test/ui/parser/issue-68730.stderr and b/src/test/ui/parser/issue-68730.stderr differ diff --git a/src/test/ui/parser/issue-68890-2.rs b/src/test/ui/parser/issue-68890-2.rs new file mode 100644 index 00000000000..ae022460468 --- /dev/null +++ b/src/test/ui/parser/issue-68890-2.rs @@ -0,0 +1,6 @@ +fn main() {} + +type X<'a> = (?'a) +; +//~^ ERROR `?` may only modify trait bounds, not lifetime bounds +//~| ERROR at least one trait is required for an object type +//~| WARN trait objects without an explicit `dyn` are deprecated diff --git a/src/test/ui/parser/issue-68890-2.stderr b/src/test/ui/parser/issue-68890-2.stderr new file mode 100644 index 00000000000..d475c79cb27 --- /dev/null +++ b/src/test/ui/parser/issue-68890-2.stderr @@ -0,0 +1,22 @@ +error: `?` may only modify trait bounds, not lifetime bounds + --> $DIR/issue-68890-2.rs:3:15 + | +LL | type X<'a> = (?'a) +; + | ^ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-68890-2.rs:3:14 + | +LL | type X<'a> = (?'a) +; + | ^^^^^^^ help: use `dyn`: `dyn (?'a) +` + | + = note: `#[warn(bare_trait_objects)]` on by default + +error[E0224]: at least one trait is required for an object type + --> $DIR/issue-68890-2.rs:3:14 + | +LL | type X<'a> = (?'a) +; + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/issue-68890.rs b/src/test/ui/parser/issue-68890.rs index a7c5a5e1300..bab4ed7f800 100644 --- a/src/test/ui/parser/issue-68890.rs +++ b/src/test/ui/parser/issue-68890.rs @@ -1,4 +1,4 @@ enum e{A((?'a a+?+l))} //~^ ERROR `?` may only modify trait bounds, not lifetime bounds //~| ERROR expected one of `)`, `+`, or `,` -//~| ERROR expected trait bound, not lifetime bound +//~| ERROR expected item, found `)` diff --git a/src/test/ui/parser/issue-68890.stderr b/src/test/ui/parser/issue-68890.stderr index 9bb8761b67b..2a3bf6b41f0 100644 --- a/src/test/ui/parser/issue-68890.stderr +++ b/src/test/ui/parser/issue-68890.stderr @@ -10,11 +10,11 @@ error: expected one of `)`, `+`, or `,`, found `a` LL | enum e{A((?'a a+?+l))} | ^ expected one of `)`, `+`, or `,` -error: expected trait bound, not lifetime bound - --> $DIR/issue-68890.rs:1:11 +error: expected item, found `)` + --> $DIR/issue-68890.rs:1:21 | LL | enum e{A((?'a a+?+l))} - | ^^^ + | ^ expected item error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs new file mode 100644 index 00000000000..613b3c98561 --- /dev/null +++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs @@ -0,0 +1,7 @@ +// Semantically, a free `const` item cannot omit its body. + +fn main() {} + +const A: u8; //~ ERROR free constant item without body +const B; //~ ERROR free constant item without body +//~^ ERROR missing type for `const` item diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr new file mode 100644 index 00000000000..4e97229fa1a --- /dev/null +++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr @@ -0,0 +1,24 @@ +error: free constant item without body + --> $DIR/item-free-const-no-body-semantic-fail.rs:5:1 + | +LL | const A: u8; + | ^^^^^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + +error: free constant item without body + --> $DIR/item-free-const-no-body-semantic-fail.rs:6:1 + | +LL | const B; + | ^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + +error: missing type for `const` item + --> $DIR/item-free-const-no-body-semantic-fail.rs:6:7 + | +LL | const B; + | ^ help: provide a type for the item: `B: [type error]` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs b/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs new file mode 100644 index 00000000000..acfdd3c363f --- /dev/null +++ b/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs @@ -0,0 +1,8 @@ +// Syntactically, a free `const` item can omit its body. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +const X: u8; diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs new file mode 100644 index 00000000000..780479e3d26 --- /dev/null +++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs @@ -0,0 +1,11 @@ +// Semantically, a free `static` item cannot omit its body. + +fn main() {} + +static A: u8; //~ ERROR free static item without body +static B; //~ ERROR free static item without body +//~^ ERROR missing type for `static` item + +static mut C: u8; //~ ERROR free static item without body +static mut D; //~ ERROR free static item without body +//~^ ERROR missing type for `static mut` item diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr new file mode 100644 index 00000000000..60b7bb34c69 --- /dev/null +++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr @@ -0,0 +1,46 @@ +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:5:1 + | +LL | static A: u8; + | ^^^^^^^^^^^^- + | | + | help: provide a definition for the static: `= ;` + +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:6:1 + | +LL | static B; + | ^^^^^^^^- + | | + | help: provide a definition for the static: `= ;` + +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:9:1 + | +LL | static mut C: u8; + | ^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the static: `= ;` + +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:10:1 + | +LL | static mut D; + | ^^^^^^^^^^^^- + | | + | help: provide a definition for the static: `= ;` + +error: missing type for `static` item + --> $DIR/item-free-static-no-body-semantic-fail.rs:6:8 + | +LL | static B; + | ^ help: provide a type for the item: `B: [type error]` + +error: missing type for `static mut` item + --> $DIR/item-free-static-no-body-semantic-fail.rs:10:12 + | +LL | static mut D; + | ^ help: provide a type for the item: `D: [type error]` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs b/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs new file mode 100644 index 00000000000..db0039204d8 --- /dev/null +++ b/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs @@ -0,0 +1,8 @@ +// Syntactically, a free `const` item can omit its body. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +static X: u8; diff --git a/src/test/ui/parser/item-free-type-bounds-semantic-fail.rs b/src/test/ui/parser/item-free-type-bounds-semantic-fail.rs new file mode 100644 index 00000000000..9db4111fbab --- /dev/null +++ b/src/test/ui/parser/item-free-type-bounds-semantic-fail.rs @@ -0,0 +1,20 @@ +fn main() {} + +fn semantics() { + type A: Ord; + //~^ ERROR bounds on `type`s in this context have no effect + //~| ERROR free type alias without body + type B: Ord = u8; + //~^ ERROR bounds on `type`s in this context have no effect + type C: Ord where 'static: 'static = u8; + //~^ ERROR bounds on `type`s in this context have no effect + type D<_T>: Ord; + //~^ ERROR bounds on `type`s in this context have no effect + //~| ERROR free type alias without body + type E<_T>: Ord = u8; + //~^ ERROR bounds on `type`s in this context have no effect + //~| ERROR type parameter `_T` is unused + type F<_T>: Ord where 'static: 'static = u8; + //~^ ERROR bounds on `type`s in this context have no effect + //~| ERROR type parameter `_T` is unused +} diff --git a/src/test/ui/parser/item-free-type-bounds-semantic-fail.stderr b/src/test/ui/parser/item-free-type-bounds-semantic-fail.stderr new file mode 100644 index 00000000000..1b086512891 --- /dev/null +++ b/src/test/ui/parser/item-free-type-bounds-semantic-fail.stderr @@ -0,0 +1,67 @@ +error: free type alias without body + --> $DIR/item-free-type-bounds-semantic-fail.rs:4:5 + | +LL | type A: Ord; + | ^^^^^^^^^^^- + | | + | help: provide a definition for the type: `= ;` + +error: bounds on `type`s in this context have no effect + --> $DIR/item-free-type-bounds-semantic-fail.rs:4:13 + | +LL | type A: Ord; + | ^^^ + +error: bounds on `type`s in this context have no effect + --> $DIR/item-free-type-bounds-semantic-fail.rs:7:13 + | +LL | type B: Ord = u8; + | ^^^ + +error: bounds on `type`s in this context have no effect + --> $DIR/item-free-type-bounds-semantic-fail.rs:9:13 + | +LL | type C: Ord where 'static: 'static = u8; + | ^^^ + +error: free type alias without body + --> $DIR/item-free-type-bounds-semantic-fail.rs:11:5 + | +LL | type D<_T>: Ord; + | ^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the type: `= ;` + +error: bounds on `type`s in this context have no effect + --> $DIR/item-free-type-bounds-semantic-fail.rs:11:17 + | +LL | type D<_T>: Ord; + | ^^^ + +error: bounds on `type`s in this context have no effect + --> $DIR/item-free-type-bounds-semantic-fail.rs:14:17 + | +LL | type E<_T>: Ord = u8; + | ^^^ + +error: bounds on `type`s in this context have no effect + --> $DIR/item-free-type-bounds-semantic-fail.rs:17:17 + | +LL | type F<_T>: Ord where 'static: 'static = u8; + | ^^^ + +error[E0091]: type parameter `_T` is unused + --> $DIR/item-free-type-bounds-semantic-fail.rs:14:12 + | +LL | type E<_T>: Ord = u8; + | ^^ unused type parameter + +error[E0091]: type parameter `_T` is unused + --> $DIR/item-free-type-bounds-semantic-fail.rs:17:12 + | +LL | type F<_T>: Ord where 'static: 'static = u8; + | ^^ unused type parameter + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0091`. diff --git a/src/test/ui/parser/item-free-type-bounds-syntactic-pass.rs b/src/test/ui/parser/item-free-type-bounds-syntactic-pass.rs new file mode 100644 index 00000000000..58fc926d08f --- /dev/null +++ b/src/test/ui/parser/item-free-type-bounds-syntactic-pass.rs @@ -0,0 +1,13 @@ +// check-pass + +fn main() {} + +#[cfg(FALSE)] +fn syntax() { + type A: Ord; + type B: Ord = u8; + type C: Ord where 'static: 'static = u8; + type D<_T>: Ord; + type E<_T>: Ord = u8; + type F<_T>: Ord where 'static: 'static = u8; +} diff --git a/src/test/ui/parser/labeled-no-colon-expr.rs b/src/test/ui/parser/labeled-no-colon-expr.rs new file mode 100644 index 00000000000..db9ef52c1ae --- /dev/null +++ b/src/test/ui/parser/labeled-no-colon-expr.rs @@ -0,0 +1,17 @@ +#![feature(label_break_value)] + +fn main() { + 'l0 while false {} //~ ERROR labeled expression must be followed by `:` + 'l1 for _ in 0..1 {} //~ ERROR labeled expression must be followed by `:` + 'l2 loop {} //~ ERROR labeled expression must be followed by `:` + 'l3 {} //~ ERROR labeled expression must be followed by `:` + 'l4 0; //~ ERROR labeled expression must be followed by `:` + //~^ ERROR expected `while`, `for`, `loop` or `{` + + macro_rules! m { + ($b:block) => { + 'l5 $b; //~ ERROR cannot use a `block` macro fragment here + } + } + m!({}); //~ ERROR labeled expression must be followed by `:` +} diff --git a/src/test/ui/parser/labeled-no-colon-expr.stderr b/src/test/ui/parser/labeled-no-colon-expr.stderr new file mode 100644 index 00000000000..4f5e8f78aa0 --- /dev/null +++ b/src/test/ui/parser/labeled-no-colon-expr.stderr @@ -0,0 +1,89 @@ +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:4:5 + | +LL | 'l0 while false {} + | ----^^^^^^^^^^^^^^ + | | | + | | help: add `:` after the label + | the label + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:5:5 + | +LL | 'l1 for _ in 0..1 {} + | ----^^^^^^^^^^^^^^^^ + | | | + | | help: add `:` after the label + | the label + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:6:5 + | +LL | 'l2 loop {} + | ----^^^^^^^ + | | | + | | help: add `:` after the label + | the label + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:7:5 + | +LL | 'l3 {} + | ----^^ + | | | + | | help: add `:` after the label + | the label + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/labeled-no-colon-expr.rs:8:9 + | +LL | 'l4 0; + | ^ expected `while`, `for`, `loop` or `{` after a label + +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:8:9 + | +LL | 'l4 0; + | ----^ + | | | + | | help: add `:` after the label + | the label + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: cannot use a `block` macro fragment here + --> $DIR/labeled-no-colon-expr.rs:13:17 + | +LL | 'l5 $b; + | ----^^ + | | + | the `block` fragment is within this context +... +LL | m!({}); + | ------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: labeled expression must be followed by `:` + --> $DIR/labeled-no-colon-expr.rs:16:8 + | +LL | 'l5 $b; + | ---- help: add `:` after the label + | | + | the label +... +LL | m!({}); + | ^^ + | + = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/parser/macro/pub-item-macro.rs b/src/test/ui/parser/macro/pub-item-macro.rs index bae90227c62..f5f8a01e6a4 100644 --- a/src/test/ui/parser/macro/pub-item-macro.rs +++ b/src/test/ui/parser/macro/pub-item-macro.rs @@ -1,12 +1,15 @@ // Issue #14660 -macro_rules! priv_x { () => { - static x: u32 = 0; -}} +macro_rules! priv_x { + () => { + static x: u32 = 0; + }; +} macro_rules! pub_x { () => { pub priv_x!(); //~ ERROR can't qualify macro invocation with `pub` - //~^ HELP try adjusting the macro to put `pub` inside the invocation + //~^ HELP remove the visibility + //~| HELP try adjusting the macro to put `pub` inside the invocation }} mod foo { diff --git a/src/test/ui/parser/macro/pub-item-macro.stderr b/src/test/ui/parser/macro/pub-item-macro.stderr index 49644cf6a0e..4ff96532e03 100644 --- a/src/test/ui/parser/macro/pub-item-macro.stderr +++ b/src/test/ui/parser/macro/pub-item-macro.stderr @@ -1,8 +1,8 @@ error: can't qualify macro invocation with `pub` - --> $DIR/pub-item-macro.rs:8:5 + --> $DIR/pub-item-macro.rs:10:5 | LL | pub priv_x!(); - | ^^^ + | ^^^ help: remove the visibility ... LL | pub_x!(); | --------- in this macro invocation @@ -11,16 +11,16 @@ LL | pub_x!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0603]: static `x` is private - --> $DIR/pub-item-macro.rs:17:23 + --> $DIR/pub-item-macro.rs:20:23 | LL | let y: u32 = foo::x; | ^ this static is private | note: the static `x` is defined here - --> $DIR/pub-item-macro.rs:4:5 + --> $DIR/pub-item-macro.rs:5:9 | -LL | static x: u32 = 0; - | ^^^^^^^^^^^^^^^^^^ +LL | static x: u32 = 0; + | ^^^^^^^^^^^^^^^^^^ ... LL | pub_x!(); | --------- in this macro invocation diff --git a/src/test/ui/parser/macro/trait-non-item-macros.rs b/src/test/ui/parser/macro/trait-non-item-macros.rs index 5021886bf98..97fb564bf64 100644 --- a/src/test/ui/parser/macro/trait-non-item-macros.rs +++ b/src/test/ui/parser/macro/trait-non-item-macros.rs @@ -1,10 +1,13 @@ macro_rules! bah { - ($a:expr) => ($a) - //~^ ERROR expected one of `async` + ($a:expr) => { + $a + }; //~^ ERROR macro expansion ignores token `2` and any following } -trait bar { +trait Bar { bah!(2); } -fn main() {} +fn main() { + let _recovery_witness: () = 0; //~ ERROR mismatched types +} diff --git a/src/test/ui/parser/macro/trait-non-item-macros.stderr b/src/test/ui/parser/macro/trait-non-item-macros.stderr index 5a89b5b936f..35e5bfe62f5 100644 --- a/src/test/ui/parser/macro/trait-non-item-macros.stderr +++ b/src/test/ui/parser/macro/trait-non-item-macros.stderr @@ -1,13 +1,22 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `2` - --> $DIR/trait-non-item-macros.rs:2:19 +error: macro expansion ignores token `2` and any following + --> $DIR/trait-non-item-macros.rs:3:9 | -LL | ($a:expr) => ($a) - | ^^ expected one of 9 possible tokens +LL | $a + | ^^ ... LL | bah!(2); - | -------- in this macro invocation + | -------- caused by the macro expansion here | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + = note: the usage of `bah!` is likely invalid in trait item context -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/trait-non-item-macros.rs:12:33 + | +LL | let _recovery_witness: () = 0; + | -- ^ expected `()`, found integer + | | + | expected due to this + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/macro/trait-object-macro-matcher.rs b/src/test/ui/parser/macro/trait-object-macro-matcher.rs index 80d867d3b56..170ac22780b 100644 --- a/src/test/ui/parser/macro/trait-object-macro-matcher.rs +++ b/src/test/ui/parser/macro/trait-object-macro-matcher.rs @@ -2,9 +2,14 @@ // `ty` matcher in particular doesn't accept a single lifetime macro_rules! m { - ($t: ty) => ( let _: $t; ) + ($t: ty) => { + let _: $t; + }; } fn main() { - m!('static); //~ ERROR expected type, found `'static` + m!('static); + //~^ ERROR lifetime in trait object type must be followed by `+` + //~| ERROR at least one trait is required for an object type + //~| WARN trait objects without an explicit `dyn` are deprecated } diff --git a/src/test/ui/parser/macro/trait-object-macro-matcher.stderr b/src/test/ui/parser/macro/trait-object-macro-matcher.stderr index f02f60e4bfb..230733371dd 100644 --- a/src/test/ui/parser/macro/trait-object-macro-matcher.stderr +++ b/src/test/ui/parser/macro/trait-object-macro-matcher.stderr @@ -1,8 +1,22 @@ -error: expected type, found `'static` - --> $DIR/trait-object-macro-matcher.rs:9:8 +error: lifetime in trait object type must be followed by `+` + --> $DIR/trait-object-macro-matcher.rs:11:8 | LL | m!('static); - | ^^^^^^^ expected type + | ^^^^^^^ -error: aborting due to previous error +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/trait-object-macro-matcher.rs:11:8 + | +LL | m!('static); + | ^^^^^^^ help: use `dyn`: `dyn 'static` + | + = note: `#[warn(bare_trait_objects)]` on by default + +error[E0224]: at least one trait is required for an object type + --> $DIR/trait-object-macro-matcher.rs:11:8 + | +LL | m!('static); + | ^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs index 9f02a7a997b..8f46970b1af 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs @@ -1,12 +1,13 @@ +fn main() {} + impl T for () { //~ ERROR cannot find trait `T` in this scope fn foo(&self) {} -trait T { //~ ERROR expected one of +trait T { //~ ERROR trait is not supported in `trait`s or `impl`s fn foo(&self); } -pub(crate) struct Bar(); +pub(crate) struct Bar(); //~ ERROR struct is not supported in `trait`s or `impl`s -fn main() {} //~ ERROR this file contains an unclosed delimiter diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr index a23cfeac58f..1655a968395 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/missing-close-brace-in-impl-trait.rs:12:52 + --> $DIR/missing-close-brace-in-impl-trait.rs:13:52 | LL | impl T for () { | - unclosed delimiter @@ -7,27 +7,24 @@ LL | impl T for () { LL | | ^ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `trait` - --> $DIR/missing-close-brace-in-impl-trait.rs:5:1 +error: trait is not supported in `trait`s or `impl`s + --> $DIR/missing-close-brace-in-impl-trait.rs:7:1 | -LL | impl T for () { - | - unclosed delimiter -LL | -LL | fn foo(&self) {} - | - - | | - | expected one of 10 possible tokens - | help: `}` may belong here -LL | LL | trait T { - | ^^^^^ unexpected token + | ^^^^^^^ + +error: struct is not supported in `trait`s or `impl`s + --> $DIR/missing-close-brace-in-impl-trait.rs:11:1 + | +LL | pub(crate) struct Bar(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0405]: cannot find trait `T` in this scope - --> $DIR/missing-close-brace-in-impl-trait.rs:1:6 + --> $DIR/missing-close-brace-in-impl-trait.rs:3:6 | LL | impl T for () { | ^ not found in this scope -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0405`. diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs index 5ec5d45bbe7..b6932deb5c0 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs @@ -1,11 +1,11 @@ trait T { -//~^ ERROR `main` function not found in crate `missing_close_brace_in_trait` fn foo(&self); pub(crate) struct Bar(); -//~^ ERROR expected one of +//~^ ERROR struct is not supported in `trait`s or `impl`s impl T for Bar { +//~^ ERROR implementation is not supported in `trait`s or `impl`s fn foo(&self) {} } diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr index 21364012782..43a3883357a 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr @@ -7,24 +7,17 @@ LL | trait T { LL | fn main() {} | ^ -error: expected one of `async`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found keyword `struct` - --> $DIR/missing-close-brace-in-trait.rs:5:12 +error: struct is not supported in `trait`s or `impl`s + --> $DIR/missing-close-brace-in-trait.rs:4:1 | LL | pub(crate) struct Bar(); - | ^^^^^^ expected one of 7 possible tokens + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0601]: `main` function not found in crate `missing_close_brace_in_trait` - --> $DIR/missing-close-brace-in-trait.rs:1:1 +error: implementation is not supported in `trait`s or `impl`s + --> $DIR/missing-close-brace-in-trait.rs:7:1 | -LL | / trait T { -LL | | -LL | | fn foo(&self); -LL | | -... | -LL | | -LL | | fn main() {} - | |________________________________________________________________^ consider adding a `main` function to `$DIR/missing-close-brace-in-trait.rs` +LL | impl T for Bar { + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr index 311f1768d82..f1be5dc5ba7 100644 --- a/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr +++ b/src/test/ui/parser/mismatched-delim-brace-empty-block.stderr @@ -1,14 +1,8 @@ error: unexpected closing delimiter: `}` --> $DIR/mismatched-delim-brace-empty-block.rs:5:1 | -LL | fn main() { - | ___________- -LL | | -LL | | } - | |_- this block is empty, you might have not meant to close it -LL | let _ = (); -LL | } - | ^ unexpected closing delimiter +LL | } + | ^ unexpected closing delimiter error: aborting due to previous error diff --git a/src/test/ui/parser/missing-semicolon.rs b/src/test/ui/parser/missing-semicolon.rs new file mode 100644 index 00000000000..a24dfa761a6 --- /dev/null +++ b/src/test/ui/parser/missing-semicolon.rs @@ -0,0 +1,8 @@ +macro_rules! m { + ($($e1:expr),*; $($e2:expr),*) => { + $( let x = $e1 )*; //~ ERROR expected one of `.`, `;`, `?`, or + $( println!("{}", $e2) )*; + } +} + +fn main() { m!(0, 0; 0, 0); } diff --git a/src/test/ui/parser/missing-semicolon.stderr b/src/test/ui/parser/missing-semicolon.stderr new file mode 100644 index 00000000000..26cb3d13d9c --- /dev/null +++ b/src/test/ui/parser/missing-semicolon.stderr @@ -0,0 +1,13 @@ +error: expected one of `.`, `;`, `?`, or an operator, found keyword `let` + --> $DIR/missing-semicolon.rs:3:12 + | +LL | $( let x = $e1 )*; + | ^^^ expected one of `.`, `;`, `?`, or an operator +... +LL | fn main() { m!(0, 0; 0, 0); } + | --------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/ui/parser/mod_file_not_exist.rs b/src/test/ui/parser/mod_file_not_exist.rs index e662c707a38..f4a27b52ec5 100644 --- a/src/test/ui/parser/mod_file_not_exist.rs +++ b/src/test/ui/parser/mod_file_not_exist.rs @@ -1,8 +1,9 @@ // ignore-windows mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` -//~^ HELP name the file either not_a_real_file.rs or not_a_real_file/mod.rs inside the directory +//~^ HELP to create the module `not_a_real_file`, create file fn main() { assert_eq!(mod_file_aux::bar(), 10); + //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr index dadf4b29dcf..087ae9fe3e0 100644 --- a/src/test/ui/parser/mod_file_not_exist.stderr +++ b/src/test/ui/parser/mod_file_not_exist.stderr @@ -1,11 +1,18 @@ error[E0583]: file not found for module `not_a_real_file` - --> $DIR/mod_file_not_exist.rs:3:5 + --> $DIR/mod_file_not_exist.rs:3:1 | LL | mod not_a_real_file; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | - = help: name the file either not_a_real_file.rs or not_a_real_file/mod.rs inside the directory "$DIR" + = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error: aborting due to previous error +error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` + --> $DIR/mod_file_not_exist.rs:7:16 + | +LL | assert_eq!(mod_file_aux::bar(), 10); + | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0583`. +Some errors have detailed explanations: E0433, E0583. +For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/parser/mod_file_not_exist_windows.rs b/src/test/ui/parser/mod_file_not_exist_windows.rs index 0cd9e9c799f..4b7d7a02bbe 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.rs +++ b/src/test/ui/parser/mod_file_not_exist_windows.rs @@ -1,8 +1,9 @@ // only-windows mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` -//~^ HELP name the file either not_a_real_file.rs or not_a_real_file\mod.rs inside the directory +//~^ HELP to create the module `not_a_real_file`, create file fn main() { assert_eq!(mod_file_aux::bar(), 10); + //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist_windows.stderr b/src/test/ui/parser/mod_file_not_exist_windows.stderr index 60ae00abab1..d67205cfdf1 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.stderr +++ b/src/test/ui/parser/mod_file_not_exist_windows.stderr @@ -1,11 +1,18 @@ error[E0583]: file not found for module `not_a_real_file` - --> $DIR/mod_file_not_exist_windows.rs:3:5 + --> $DIR/mod_file_not_exist_windows.rs:3:1 | LL | mod not_a_real_file; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | - = help: name the file either not_a_real_file.rs or not_a_real_file/mod.rs inside the directory "$DIR" + = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error: aborting due to previous error +error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` + --> $DIR/mod_file_not_exist_windows.rs:7:16 + | +LL | assert_eq!(mod_file_aux::bar(), 10); + | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0583`. +Some errors have detailed explanations: E0433, E0583. +For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/ui/parser/mod_file_with_path_attr.stderr b/src/test/ui/parser/mod_file_with_path_attr.stderr index 004b5d7963a..cd1add73d58 100644 --- a/src/test/ui/parser/mod_file_with_path_attr.stderr +++ b/src/test/ui/parser/mod_file_with_path_attr.stderr @@ -1,8 +1,8 @@ error: couldn't read $DIR/not_a_real_file.rs: $FILE_NOT_FOUND_MSG (os error 2) - --> $DIR/mod_file_with_path_attr.rs:4:5 + --> $DIR/mod_file_with_path_attr.rs:4:1 | LL | mod m; - | ^ + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs index 66fd5893af5..8b83d6ab2f8 100644 --- a/src/test/ui/parser/mut-patterns.rs +++ b/src/test/ui/parser/mut-patterns.rs @@ -9,6 +9,8 @@ pub fn main() { let mut _ = 0; //~ ERROR `mut` must be followed by a named binding let mut (_, _) = (0, 0); //~ ERROR `mut` must be followed by a named binding + let mut (x @ y) = 0; //~ ERROR `mut` must be attached to each individual binding + let mut mut x = 0; //~^ ERROR `mut` on a binding may not be repeated //~| remove the additional `mut`s diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr index 5f4c349d7d6..9a6af7394bf 100644 --- a/src/test/ui/parser/mut-patterns.stderr +++ b/src/test/ui/parser/mut-patterns.stderr @@ -14,14 +14,22 @@ LL | let mut (_, _) = (0, 0); | = note: `mut` may be followed by `variable` and `variable @ pattern` +error: `mut` must be attached to each individual binding + --> $DIR/mut-patterns.rs:12:9 + | +LL | let mut (x @ y) = 0; + | ^^^^^^^^^^^ help: add `mut` to each binding: `(mut x @ mut y)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + error: `mut` on a binding may not be repeated - --> $DIR/mut-patterns.rs:12:13 + --> $DIR/mut-patterns.rs:14:13 | LL | let mut mut x = 0; | ^^^ help: remove the additional `mut`s error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:17:9 + --> $DIR/mut-patterns.rs:19:9 | LL | let mut Foo { x: x } = Foo { x: 3 }; | ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }` @@ -29,7 +37,7 @@ LL | let mut Foo { x: x } = Foo { x: 3 }; = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:21:9 + --> $DIR/mut-patterns.rs:23:9 | LL | let mut Foo { x } = Foo { x: 3 }; | ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }` @@ -37,13 +45,13 @@ LL | let mut Foo { x } = Foo { x: 3 }; = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` on a binding may not be repeated - --> $DIR/mut-patterns.rs:26:13 + --> $DIR/mut-patterns.rs:28:13 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^ help: remove the additional `mut`s error: expected identifier, found reserved keyword `yield` - --> $DIR/mut-patterns.rs:26:17 + --> $DIR/mut-patterns.rs:28:17 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^ expected identifier, found reserved keyword @@ -54,7 +62,7 @@ LL | let mut mut r#yield(become, await) = r#yield(0, 0); | ^^^^^^^ error: expected identifier, found reserved keyword `become` - --> $DIR/mut-patterns.rs:26:23 + --> $DIR/mut-patterns.rs:28:23 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^^ expected identifier, found reserved keyword @@ -65,7 +73,7 @@ LL | let mut mut yield(r#become, await) = r#yield(0, 0); | ^^^^^^^^ error: expected identifier, found keyword `await` - --> $DIR/mut-patterns.rs:26:31 + --> $DIR/mut-patterns.rs:28:31 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^ expected identifier, found keyword @@ -76,7 +84,7 @@ LL | let mut mut yield(become, r#await) = r#yield(0, 0); | ^^^^^^^ error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:26:9 + --> $DIR/mut-patterns.rs:28:9 | LL | let mut mut yield(become, await) = r#yield(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `r#yield(mut r#become, mut r#await)` @@ -84,7 +92,7 @@ LL | let mut mut yield(become, await) = r#yield(0, 0); = note: `mut` may be followed by `variable` and `variable @ pattern` error: `mut` must be attached to each individual binding - --> $DIR/mut-patterns.rs:35:9 + --> $DIR/mut-patterns.rs:37:9 | LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))` @@ -92,7 +100,7 @@ LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) = note: `mut` may be followed by `variable` and `variable @ pattern` error: expected identifier, found `x` - --> $DIR/mut-patterns.rs:42:21 + --> $DIR/mut-patterns.rs:44:21 | LL | let mut $p = 0; | ^^ expected identifier @@ -102,5 +110,5 @@ LL | foo!(x); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors diff --git a/src/test/ui/parser/pub-method-macro.rs b/src/test/ui/parser/pub-method-macro.rs index f04af1a0d65..0183bdcf622 100644 --- a/src/test/ui/parser/pub-method-macro.rs +++ b/src/test/ui/parser/pub-method-macro.rs @@ -15,7 +15,8 @@ mod bleh { impl S { pub defn!(f); //~ ERROR can't qualify macro invocation with `pub` - //~^ HELP try adjusting the macro to put `pub` inside the invocation + //~^ HELP remove the visibility + //~| HELP try adjusting the macro to put `pub` inside the invocation } } diff --git a/src/test/ui/parser/pub-method-macro.stderr b/src/test/ui/parser/pub-method-macro.stderr index 7b0fe493461..7c7a909267a 100644 --- a/src/test/ui/parser/pub-method-macro.stderr +++ b/src/test/ui/parser/pub-method-macro.stderr @@ -2,7 +2,7 @@ error: can't qualify macro invocation with `pub` --> $DIR/pub-method-macro.rs:17:9 | LL | pub defn!(f); - | ^^^ + | ^^^ help: remove the visibility | = help: try adjusting the macro to put `pub` inside the invocation diff --git a/src/test/ui/parser/raw-byte-string-eof.stderr b/src/test/ui/parser/raw-byte-string-eof.stderr index 65fa89f2a81..d5f22e2a1a8 100644 --- a/src/test/ui/parser/raw-byte-string-eof.stderr +++ b/src/test/ui/parser/raw-byte-string-eof.stderr @@ -1,4 +1,4 @@ -error: unterminated raw string +error[E0748]: unterminated raw string --> $DIR/raw-byte-string-eof.rs:2:5 | LL | br##"a"#; @@ -8,3 +8,4 @@ LL | br##"a"#; error: aborting due to previous error +For more information about this error, try `rustc --explain E0748`. diff --git a/src/test/ui/parser/raw-str-unterminated.stderr b/src/test/ui/parser/raw-str-unterminated.stderr index 67792eb91e5..077f763f154 100644 --- a/src/test/ui/parser/raw-str-unterminated.stderr +++ b/src/test/ui/parser/raw-str-unterminated.stderr @@ -1,4 +1,4 @@ -error: unterminated raw string +error[E0748]: unterminated raw string --> $DIR/raw-str-unterminated.rs:2:5 | LL | r#" string literal goes on @@ -8,3 +8,4 @@ LL | r#" string literal goes on error: aborting due to previous error +For more information about this error, try `rustc --explain E0748`. diff --git a/src/test/ui/parser/raw/raw_string.stderr b/src/test/ui/parser/raw/raw_string.stderr index 5572511881d..0f1d7e4651d 100644 --- a/src/test/ui/parser/raw/raw_string.stderr +++ b/src/test/ui/parser/raw/raw_string.stderr @@ -1,4 +1,4 @@ -error: unterminated raw string +error[E0748]: unterminated raw string --> $DIR/raw_string.rs:2:13 | LL | let x = r##"lol"#; @@ -8,3 +8,4 @@ LL | let x = r##"lol"#; error: aborting due to previous error +For more information about this error, try `rustc --explain E0748`. diff --git a/src/test/ui/parser/recovery-attr-on-if.rs b/src/test/ui/parser/recovery-attr-on-if.rs deleted file mode 100644 index 0d1f5be7b49..00000000000 --- a/src/test/ui/parser/recovery-attr-on-if.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - #[attr] if true {}; - //~^ ERROR cannot find attribute - //~| ERROR attributes are not yet allowed on `if` expressions - #[attr] if true {}; - //~^ ERROR cannot find attribute - //~| ERROR attributes are not yet allowed on `if` expressions - let _recovery_witness: () = 0; //~ ERROR mismatched types -} diff --git a/src/test/ui/parser/recovery-attr-on-if.stderr b/src/test/ui/parser/recovery-attr-on-if.stderr deleted file mode 100644 index a02846827c9..00000000000 --- a/src/test/ui/parser/recovery-attr-on-if.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error: attributes are not yet allowed on `if` expressions - --> $DIR/recovery-attr-on-if.rs:2:5 - | -LL | #[attr] if true {}; - | ^^^^^^^ - -error: attributes are not yet allowed on `if` expressions - --> $DIR/recovery-attr-on-if.rs:5:5 - | -LL | #[attr] if true {}; - | ^^^^^^^ - -error: cannot find attribute `attr` in this scope - --> $DIR/recovery-attr-on-if.rs:5:7 - | -LL | #[attr] if true {}; - | ^^^^ - -error: cannot find attribute `attr` in this scope - --> $DIR/recovery-attr-on-if.rs:2:7 - | -LL | #[attr] if true {}; - | ^^^^ - -error[E0308]: mismatched types - --> $DIR/recovery-attr-on-if.rs:8:33 - | -LL | let _recovery_witness: () = 0; - | -- ^ expected `()`, found integer - | | - | expected due to this - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/regions-out-of-scope-slice.rs b/src/test/ui/parser/regions-out-of-scope-slice.rs index 21369d0be61..d223619e1de 100644 --- a/src/test/ui/parser/regions-out-of-scope-slice.rs +++ b/src/test/ui/parser/regions-out-of-scope-slice.rs @@ -4,7 +4,7 @@ fn foo(cond: bool) { let mut x; if cond { - x = &'blk [1,2,3]; //~ ERROR expected `:`, found `[` + x = &'blk [1,2,3]; //~ ERROR borrow expressions cannot be annotated with lifetimes } } diff --git a/src/test/ui/parser/regions-out-of-scope-slice.stderr b/src/test/ui/parser/regions-out-of-scope-slice.stderr index 8d9bf0b7a04..bbc657ffd61 100644 --- a/src/test/ui/parser/regions-out-of-scope-slice.stderr +++ b/src/test/ui/parser/regions-out-of-scope-slice.stderr @@ -1,8 +1,11 @@ -error: expected `:`, found `[` - --> $DIR/regions-out-of-scope-slice.rs:7:19 +error: borrow expressions cannot be annotated with lifetimes + --> $DIR/regions-out-of-scope-slice.rs:7:13 | LL | x = &'blk [1,2,3]; - | ^ expected `:` + | ^----^^^^^^^^ + | | + | annotated with lifetime here + | help: remove the lifetime annotation error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-extern-const.rs b/src/test/ui/parser/removed-syntax-extern-const.rs deleted file mode 100644 index 71c22e62f8e..00000000000 --- a/src/test/ui/parser/removed-syntax-extern-const.rs +++ /dev/null @@ -1,6 +0,0 @@ -extern { - const i: isize; - //~^ ERROR extern items cannot be `const` -} - -fn main() {} diff --git a/src/test/ui/parser/removed-syntax-extern-const.stderr b/src/test/ui/parser/removed-syntax-extern-const.stderr deleted file mode 100644 index 2bccbd91452..00000000000 --- a/src/test/ui/parser/removed-syntax-extern-const.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: extern items cannot be `const` - --> $DIR/removed-syntax-extern-const.rs:2:5 - | -LL | const i: isize; - | ^^^^^ help: try using a static value: `static` - -error: aborting due to previous error - diff --git a/src/test/ui/parser/removed-syntax-static-fn.rs b/src/test/ui/parser/removed-syntax-static-fn.rs index 0caddb9855d..cd643b874db 100644 --- a/src/test/ui/parser/removed-syntax-static-fn.rs +++ b/src/test/ui/parser/removed-syntax-static-fn.rs @@ -2,7 +2,9 @@ struct S; impl S { static fn f() {} - //~^ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, + //~^ ERROR expected identifier, found keyword `fn` + //~| ERROR expected one of `:`, `;`, or `=` + //~| ERROR missing type for `static` item } fn main() {} diff --git a/src/test/ui/parser/removed-syntax-static-fn.stderr b/src/test/ui/parser/removed-syntax-static-fn.stderr index dfadefee23c..04e34dc16a8 100644 --- a/src/test/ui/parser/removed-syntax-static-fn.stderr +++ b/src/test/ui/parser/removed-syntax-static-fn.stderr @@ -1,10 +1,25 @@ -error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found keyword `static` - --> $DIR/removed-syntax-static-fn.rs:4:5 +error: expected identifier, found keyword `fn` + --> $DIR/removed-syntax-static-fn.rs:4:12 + | +LL | static fn f() {} + | ^^ expected identifier, found keyword + +error: expected one of `:`, `;`, or `=`, found `f` + --> $DIR/removed-syntax-static-fn.rs:4:15 | LL | impl S { - | - expected one of 10 possible tokens + | - while parsing this item list starting here +LL | static fn f() {} + | ^ expected one of `:`, `;`, or `=` +... +LL | } + | - the item list ends here + +error: missing type for `static` item + --> $DIR/removed-syntax-static-fn.rs:4:12 + | LL | static fn f() {} - | ^^^^^^ unexpected token + | ^^ help: provide a type for the item: `r#fn: ` -error: aborting due to previous error +error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/removed-syntax-with-1.stderr b/src/test/ui/parser/removed-syntax-with-1.stderr index 193138d7460..c3f747b61b9 100644 --- a/src/test/ui/parser/removed-syntax-with-1.stderr +++ b/src/test/ui/parser/removed-syntax-with-1.stderr @@ -2,8 +2,9 @@ error: expected one of `,`, `.`, `?`, `}`, or an operator, found `with` --> $DIR/removed-syntax-with-1.rs:8:25 | LL | let b = S { foo: () with a, bar: () }; - | - ^^^^ expected one of `,`, `.`, `?`, `}`, or an operator - | | + | - -^^^^ expected one of `,`, `.`, `?`, `}`, or an operator + | | | + | | help: try adding a comma: `,` | while parsing this struct error: aborting due to previous error diff --git a/src/test/ui/parser/stripped-nested-outline-mod-pass.rs b/src/test/ui/parser/stripped-nested-outline-mod-pass.rs new file mode 100644 index 00000000000..1b4669a439f --- /dev/null +++ b/src/test/ui/parser/stripped-nested-outline-mod-pass.rs @@ -0,0 +1,13 @@ +// Expansion drives parsing, so conditional compilation will strip +// out outline modules and we will never attempt parsing them. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +mod foo { + mod bar { + mod baz; // This was an error before. + } +} diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr index 54111df3423..6bb946d5b64 100644 --- a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr +++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr @@ -2,37 +2,49 @@ error: `default` is only allowed on items in `impl` definitions --> $DIR/trait-item-with-defaultness-fail-semantic.rs:6:5 | LL | default const A: u8; - | ^^^^^^^^^^^^^^^^^^^^ + | -------^^^^^^^^^^^^^ + | | + | `default` because of this error: `default` is only allowed on items in `impl` definitions --> $DIR/trait-item-with-defaultness-fail-semantic.rs:7:5 | LL | default const B: u8 = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | -------^^^^^^^^^^^^^^^^^ + | | + | `default` because of this error: `default` is only allowed on items in `impl` definitions --> $DIR/trait-item-with-defaultness-fail-semantic.rs:8:5 | LL | default type D; - | ^^^^^^^^^^^^^^^ + | -------^^^^^^^^ + | | + | `default` because of this error: `default` is only allowed on items in `impl` definitions --> $DIR/trait-item-with-defaultness-fail-semantic.rs:9:5 | LL | default type C: Ord; - | ^^^^^^^^^^^^^^^^^^^^ + | -------^^^^^^^^^^^^^ + | | + | `default` because of this error: `default` is only allowed on items in `impl` definitions --> $DIR/trait-item-with-defaultness-fail-semantic.rs:10:5 | LL | default fn f1(); - | ^^^^^^^^^^^^^^^^ + | -------^^^^^^^^^ + | | + | `default` because of this error: `default` is only allowed on items in `impl` definitions --> $DIR/trait-item-with-defaultness-fail-semantic.rs:11:5 | LL | default fn f2() {} - | ^^^^^^^^^^^^^^^^^^ + | -------^^^^^^^^ + | | + | `default` because of this error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/trait-object-lifetime-parens.rs b/src/test/ui/parser/trait-object-lifetime-parens.rs index c8b0eb684f3..5a5c19f32e8 100644 --- a/src/test/ui/parser/trait-object-lifetime-parens.rs +++ b/src/test/ui/parser/trait-object-lifetime-parens.rs @@ -6,9 +6,7 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s fn check<'a>() { let _: Box; //~ ERROR parenthesized lifetime bounds are not supported - let _: Box<('a) + Trait>; - //~^ ERROR expected type, found `'a` - //~| ERROR expected `:`, found `)` + let _: Box<('a) + Trait>; //~ ERROR lifetime in trait object type must be followed by `+` } fn main() {} diff --git a/src/test/ui/parser/trait-object-lifetime-parens.stderr b/src/test/ui/parser/trait-object-lifetime-parens.stderr index 319a308c013..1289c248275 100644 --- a/src/test/ui/parser/trait-object-lifetime-parens.stderr +++ b/src/test/ui/parser/trait-object-lifetime-parens.stderr @@ -10,19 +10,11 @@ error: parenthesized lifetime bounds are not supported LL | let _: Box; | ^^^^ help: remove the parentheses -error: expected `:`, found `)` - --> $DIR/trait-object-lifetime-parens.rs:9:19 - | -LL | let _: Box<('a) + Trait>; - | ^ expected `:` - -error: expected type, found `'a` +error: lifetime in trait object type must be followed by `+` --> $DIR/trait-object-lifetime-parens.rs:9:17 | LL | let _: Box<('a) + Trait>; - | - ^^ expected type - | | - | while parsing the type for `_` + | ^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/trait-object-trait-parens.rs b/src/test/ui/parser/trait-object-trait-parens.rs index a113de14b6f..9fbc938c4dc 100644 --- a/src/test/ui/parser/trait-object-trait-parens.rs +++ b/src/test/ui/parser/trait-object-trait-parens.rs @@ -1,15 +1,20 @@ trait Trait<'a> {} +trait Obj {} + fn f Trait<'a>)>() {} fn main() { - let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; + let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; + //~^ ERROR `?Trait` is not permitted in trait object types + //~| ERROR only auto traits can be used as additional traits + //~| WARN trait objects without an explicit `dyn` are deprecated + let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>; //~^ ERROR `?Trait` is not permitted in trait object types + //~| ERROR only auto traits can be used as additional traits //~| WARN trait objects without an explicit `dyn` are deprecated - let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>; - //~^ WARN trait objects without an explicit `dyn` are deprecated - let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; - //~^ ERROR use of undeclared lifetime name `'a` - //~| ERROR `?Trait` is not permitted in trait object types + let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>; + //~^ ERROR `?Trait` is not permitted in trait object types + //~| ERROR only auto traits can be used as additional traits //~| WARN trait objects without an explicit `dyn` are deprecated } diff --git a/src/test/ui/parser/trait-object-trait-parens.stderr b/src/test/ui/parser/trait-object-trait-parens.stderr index 4b9f49423cb..7022a66ca1a 100644 --- a/src/test/ui/parser/trait-object-trait-parens.stderr +++ b/src/test/ui/parser/trait-object-trait-parens.stderr @@ -1,44 +1,74 @@ error: `?Trait` is not permitted in trait object types - --> $DIR/trait-object-trait-parens.rs:6:25 + --> $DIR/trait-object-trait-parens.rs:8:24 | -LL | let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; - | ^^^^^^^^ +LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; + | ^^^^^^^^ error: `?Trait` is not permitted in trait object types - --> $DIR/trait-object-trait-parens.rs:11:47 + --> $DIR/trait-object-trait-parens.rs:12:17 | -LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; - | ^^^^^^^^ +LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>; + | ^^^^^^ + +error: `?Trait` is not permitted in trait object types + --> $DIR/trait-object-trait-parens.rs:16:46 + | +LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>; + | ^^^^^^^^ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/trait-object-trait-parens.rs:6:16 + --> $DIR/trait-object-trait-parens.rs:8:16 | -LL | let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (Copy) + (?Sized) + (for<'a> Trait<'a>)` +LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (Obj) + (?Sized) + (for<'a> Trait<'a>)` | = note: `#[warn(bare_trait_objects)]` on by default warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/trait-object-trait-parens.rs:9:16 + --> $DIR/trait-object-trait-parens.rs:12:16 | -LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (?Sized) + (for<'a> Trait<'a>) + (Copy)` +LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (?Sized) + (for<'a> Trait<'a>) + (Obj)` warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/trait-object-trait-parens.rs:11:16 + --> $DIR/trait-object-trait-parens.rs:16:16 + | +LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (for<'a> Trait<'a>) + (Obj) + (?Sized)` + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-object-trait-parens.rs:8:35 + | +LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; + | ----- ^^^^^^^^^^^^^^^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) + +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-object-trait-parens.rs:12:49 | -LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (for<'a> Trait<'a>) + (Copy) + (?Sized)` +LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>; + | ------------------- ^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) -error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/trait-object-trait-parens.rs:11:31 +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-object-trait-parens.rs:16:38 | -LL | fn main() { - | - help: consider introducing lifetime `'a` here: `<'a>` -... -LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; - | ^^ undeclared lifetime +LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>; + | ----------------- ^^^^^ + | | | + | | additional non-auto trait + | | trait alias used in trait object type (additional use) + | first non-auto trait + | trait alias used in trait object type (first use) -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0261`. +For more information about this error, try `rustc --explain E0225`. diff --git a/src/test/ui/parser/underscore_item_not_const.rs b/src/test/ui/parser/underscore_item_not_const.rs index 7b0d128f06f..c01ac4752e0 100644 --- a/src/test/ui/parser/underscore_item_not_const.rs +++ b/src/test/ui/parser/underscore_item_not_const.rs @@ -1,18 +1,4 @@ -// Test that various non-const items and associated consts do not permit `_` as a name. - -// Associated `const`s: - -pub trait A { - const _: () = (); //~ ERROR expected identifier, found reserved identifier `_` -} -impl A for () { - const _: () = (); //~ ERROR expected identifier, found reserved identifier `_` -} -impl dyn A { - const _: () = (); //~ ERROR expected identifier, found reserved identifier `_` -} - -// Other kinds of items: +// Test that various non-const items do not syntactically permit `_` as a name. static _: () = (); //~ ERROR expected identifier, found reserved identifier `_` struct _(); //~ ERROR expected identifier, found reserved identifier `_` diff --git a/src/test/ui/parser/underscore_item_not_const.stderr b/src/test/ui/parser/underscore_item_not_const.stderr index ebf1ff9ff1e..0bc7642dd19 100644 --- a/src/test/ui/parser/underscore_item_not_const.stderr +++ b/src/test/ui/parser/underscore_item_not_const.stderr @@ -1,92 +1,74 @@ error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:6:11 - | -LL | const _: () = (); - | ^ expected identifier, found reserved identifier - -error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:9:11 - | -LL | const _: () = (); - | ^ expected identifier, found reserved identifier - -error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:12:11 - | -LL | const _: () = (); - | ^ expected identifier, found reserved identifier - -error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:17:8 + --> $DIR/underscore_item_not_const.rs:3:8 | LL | static _: () = (); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:18:8 + --> $DIR/underscore_item_not_const.rs:4:8 | LL | struct _(); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:19:6 + --> $DIR/underscore_item_not_const.rs:5:6 | LL | enum _ {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:20:4 + --> $DIR/underscore_item_not_const.rs:6:4 | LL | fn _() {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:21:5 + --> $DIR/underscore_item_not_const.rs:7:5 | LL | mod _ {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:22:6 + --> $DIR/underscore_item_not_const.rs:8:6 | LL | type _ = (); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:23:5 + --> $DIR/underscore_item_not_const.rs:9:5 | LL | use _; | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:24:5 + --> $DIR/underscore_item_not_const.rs:10:5 | LL | use _ as g; | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:25:7 + --> $DIR/underscore_item_not_const.rs:11:7 | LL | trait _ {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:26:7 + --> $DIR/underscore_item_not_const.rs:12:7 | LL | trait _ = Copy; | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:27:14 + --> $DIR/underscore_item_not_const.rs:13:14 | LL | macro_rules! _ { () => {} } | ^ expected identifier, found reserved identifier error: expected one of `!` or `::`, found reserved identifier `_` - --> $DIR/underscore_item_not_const.rs:28:7 + --> $DIR/underscore_item_not_const.rs:14:7 | LL | union _ { f: u8 } | ^ expected one of `!` or `::` -error: aborting due to 15 previous errors +error: aborting due to 12 previous errors diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr index 026747c212a..f2186b9298e 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -15,7 +15,7 @@ LL | Some(_z @ ref _y) => {} | | | | | value borrowed here after move | value moved into `_z` here - | move occurs because `_z` has type `X` which does implement the `Copy` trait + | move occurs because `_z` has type `X` which does not implement the `Copy` trait error: cannot move out of value because it is borrowed --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:29:14 @@ -34,7 +34,7 @@ LL | Some(_z @ ref mut _y) => {} | | | | | value borrowed here after move | value moved into `_z` here - | move occurs because `_z` has type `X` which does implement the `Copy` trait + | move occurs because `_z` has type `X` which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:19 diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr index 91fdfd4f2ab..54900e958c2 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr @@ -6,7 +6,7 @@ LL | let a @ ref b = U; | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does implement the `Copy` trait + | move occurs because `a` has type `main::U` which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index ec86692dc69..f819e671436 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -6,7 +6,7 @@ LL | let a @ ref b = U; | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does implement the `Copy` trait + | move occurs because `a` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9 @@ -17,7 +17,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does implement the `Copy` trait + | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:14 @@ -27,7 +27,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does implement the `Copy` trait + | move occurs because `b` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33 @@ -37,7 +37,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does implement the `Copy` trait + | move occurs because `d` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9 @@ -48,7 +48,7 @@ LL | let a @ [ref mut b, ref c] = [U, U]; | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `[main::U; 2]` which does implement the `Copy` trait + | move occurs because `a` has type `[main::U; 2]` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:9 @@ -58,7 +58,7 @@ LL | let a @ ref b = u(); | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does implement the `Copy` trait + | move occurs because `a` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:9 @@ -69,7 +69,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does implement the `Copy` trait + | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:14 @@ -79,7 +79,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does implement the `Copy` trait + | move occurs because `b` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33 @@ -89,7 +89,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does implement the `Copy` trait + | move occurs because `d` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:9 @@ -100,7 +100,7 @@ LL | let a @ [ref mut b, ref c] = [u(), u()]; | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `[main::U; 2]` which does implement the `Copy` trait + | move occurs because `a` has type `[main::U; 2]` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:56:9 @@ -110,7 +110,7 @@ LL | a @ Some(ref b) => {} | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option` which does implement the `Copy` trait + | move occurs because `a` has type `std::option::Option` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9 @@ -121,7 +121,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<(main::U, main::U)>` which does implement the `Copy` trait + | move occurs because `a` has type `std::option::Option<(main::U, main::U)>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:19 @@ -131,7 +131,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does implement the `Copy` trait + | move occurs because `b` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 @@ -141,7 +141,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does implement the `Copy` trait + | move occurs because `d` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:9 @@ -152,7 +152,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<[main::U; 2]>` which does implement the `Copy` trait + | move occurs because `a` has type `std::option::Option<[main::U; 2]>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:9 @@ -162,7 +162,7 @@ LL | a @ Some(ref b) => {} | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option` which does implement the `Copy` trait + | move occurs because `a` has type `std::option::Option` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:9 @@ -173,7 +173,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<(main::U, main::U)>` which does implement the `Copy` trait + | move occurs because `a` has type `std::option::Option<(main::U, main::U)>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:19 @@ -183,7 +183,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does implement the `Copy` trait + | move occurs because `b` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 @@ -193,7 +193,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does implement the `Copy` trait + | move occurs because `d` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:9 @@ -204,7 +204,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<[main::U; 2]>` which does implement the `Copy` trait + | move occurs because `a` has type `std::option::Option<[main::U; 2]>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11 @@ -214,7 +214,7 @@ LL | fn f1(a @ ref b: U) {} | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does implement the `Copy` trait + | move occurs because `a` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:11 @@ -225,7 +225,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does implement the `Copy` trait + | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:20 @@ -235,7 +235,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does implement the `Copy` trait + | move occurs because `b` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31 @@ -245,7 +245,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does implement the `Copy` trait + | move occurs because `d` has type `main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:11 @@ -256,7 +256,7 @@ LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `[main::U; 2]` which does implement the `Copy` trait + | move occurs because `a` has type `[main::U; 2]` which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:22 diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index 4e96c6e1669..e74f227b5e4 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -96,7 +96,7 @@ LL | let a @ (ref mut b, ref mut c) = (U, U); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does implement the `Copy` trait + | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9 @@ -108,7 +108,7 @@ LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `&mut (main::U, [main::U; 2])` which does implement the `Copy` trait + | move occurs because `a` has type `&mut (main::U, [main::U; 2])` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:74:9 @@ -118,7 +118,7 @@ LL | let a @ &mut ref mut b = &mut U; | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `&mut main::U` which does implement the `Copy` trait + | move occurs because `a` has type `&mut main::U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:77:9 @@ -129,7 +129,7 @@ LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `&mut (main::U, main::U)` which does implement the `Copy` trait + | move occurs because `a` has type `&mut (main::U, main::U)` which does not implement the `Copy` trait error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9 diff --git a/src/test/ui/pattern/bindings-after-at/box-patterns.rs b/src/test/ui/pattern/bindings-after-at/box-patterns.rs new file mode 100644 index 00000000000..ef9669a6b9e --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/box-patterns.rs @@ -0,0 +1,36 @@ +// Test bindings-after-at with box-patterns + +// run-pass + +#![feature(bindings_after_at)] +#![feature(box_patterns)] + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +fn test(x: Option>) -> MatchArm { + match x { + ref bar @ Some(box n) if n > 0 => { + // bar is a &Option> + assert_eq!(bar, &x); + + MatchArm::Arm(0) + }, + Some(ref bar @ box n) if n < 0 => { + // bar is a &Box here + assert_eq!(**bar, n); + + MatchArm::Arm(1) + }, + _ => MatchArm::Wild, + } +} + +fn main() { + assert_eq!(test(Some(Box::new(2))), MatchArm::Arm(0)); + assert_eq!(test(Some(Box::new(-1))), MatchArm::Arm(1)); + assert_eq!(test(Some(Box::new(0))), MatchArm::Wild); +} diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr index 697a8b96e63..19e815a1ae8 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -33,7 +33,7 @@ LL | Ok(ref a @ b) | Err(b @ ref a) => { | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::NotCopy` which does implement the `Copy` trait + | move occurs because `b` has type `main::NotCopy` which does not implement the `Copy` trait error: cannot move out of value because it is borrowed --> $DIR/default-binding-modes-both-sides-independent.rs:44:9 diff --git a/src/test/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs b/src/test/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs new file mode 100644 index 00000000000..ca8826f03f1 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs @@ -0,0 +1,45 @@ +// Test bindings-after-at with or-patterns and box-patterns + +// run-pass + +#![feature(bindings_after_at)] +#![feature(or_patterns)] +#![feature(box_patterns)] + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +#[derive(Debug, PartialEq)] +enum Test { + Foo, + Bar, + Baz, + Qux, +} + +fn test(foo: Option>) -> MatchArm { + match foo { + ref bar @ Some(box Test::Foo | box Test::Bar) => { + assert_eq!(bar, &foo); + + MatchArm::Arm(0) + }, + Some(ref bar @ box Test::Baz | ref bar @ box Test::Qux) => { + assert!(**bar == Test::Baz || **bar == Test::Qux); + + MatchArm::Arm(1) + }, + _ => MatchArm::Wild, + } +} + +fn main() { + assert_eq!(test(Some(Box::new(Test::Foo))), MatchArm::Arm(0)); + assert_eq!(test(Some(Box::new(Test::Bar))), MatchArm::Arm(0)); + assert_eq!(test(Some(Box::new(Test::Baz))), MatchArm::Arm(1)); + assert_eq!(test(Some(Box::new(Test::Qux))), MatchArm::Arm(1)); + assert_eq!(test(None), MatchArm::Wild); +} diff --git a/src/test/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs b/src/test/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs new file mode 100644 index 00000000000..65c2b3741b3 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs @@ -0,0 +1,56 @@ +// Test bindings-after-at with or-patterns and slice-patterns + +// run-pass + +#![feature(bindings_after_at)] +#![feature(or_patterns)] + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +#[derive(Debug, PartialEq)] +enum Test { + Foo, + Bar, + Baz, + Qux, +} + +fn test(foo: &[Option]) -> MatchArm { + match foo { + bar @ [Some(Test::Foo), .., Some(Test::Qux | Test::Foo)] => { + assert_eq!(bar, foo); + + MatchArm::Arm(0) + }, + [.., bar @ Some(Test::Bar | Test::Qux), _] => { + assert!(bar == &Some(Test::Bar) || bar == &Some(Test::Qux)); + + MatchArm::Arm(1) + }, + _ => MatchArm::Wild, + } +} + +fn main() { + let foo = vec![ + Some(Test::Foo), + Some(Test::Bar), + Some(Test::Baz), + Some(Test::Qux), + ]; + + // path 1a + assert_eq!(test(&foo), MatchArm::Arm(0)); + // path 1b + assert_eq!(test(&[Some(Test::Foo), Some(Test::Bar), Some(Test::Foo)]), MatchArm::Arm(0)); + // path 2a + assert_eq!(test(&foo[..3]), MatchArm::Arm(1)); + // path 2b + assert_eq!(test(&[Some(Test::Bar), Some(Test::Qux), Some(Test::Baz)]), MatchArm::Arm(1)); + // path 3 + assert_eq!(test(&foo[1..2]), MatchArm::Wild); +} diff --git a/src/test/ui/pattern/bindings-after-at/or-patterns.rs b/src/test/ui/pattern/bindings-after-at/or-patterns.rs new file mode 100644 index 00000000000..a0e14004ab1 --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/or-patterns.rs @@ -0,0 +1,40 @@ +// Test bindings-after-at with or-patterns + +// run-pass + +#![feature(bindings_after_at)] +#![feature(or_patterns)] + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +enum Test { + Foo, + Bar, + Baz, + Qux, +} + +fn test(foo: Option) -> MatchArm { + match foo { + bar @ Some(Test::Foo | Test::Bar) => { + assert!(bar == Some(Test::Foo) || bar == Some(Test::Bar)); + + MatchArm::Arm(0) + }, + Some(_) => MatchArm::Arm(1), + _ => MatchArm::Wild, + } +} + +fn main() { + assert_eq!(test(Some(Test::Foo)), MatchArm::Arm(0)); + assert_eq!(test(Some(Test::Bar)), MatchArm::Arm(0)); + assert_eq!(test(Some(Test::Baz)), MatchArm::Arm(1)); + assert_eq!(test(Some(Test::Qux)), MatchArm::Arm(1)); + assert_eq!(test(None), MatchArm::Wild); +} diff --git a/src/test/ui/pattern/bindings-after-at/slice-patterns.rs b/src/test/ui/pattern/bindings-after-at/slice-patterns.rs new file mode 100644 index 00000000000..7e50527af0b --- /dev/null +++ b/src/test/ui/pattern/bindings-after-at/slice-patterns.rs @@ -0,0 +1,40 @@ +// Test bindings-after-at with slice-patterns + +// run-pass + +#![feature(bindings_after_at)] + +#[derive(Debug, PartialEq)] +enum MatchArm { + Arm(usize), + Wild, +} + +fn test(foo: &[i32]) -> MatchArm { + match foo { + [bar @ .., n] if n == &5 => { + for i in bar { + assert!(i < &5); + } + + MatchArm::Arm(0) + }, + bar @ [x0, .., xn] => { + assert_eq!(x0, &1); + assert_eq!(x0, &1); + assert_eq!(xn, &4); + assert_eq!(bar, &[1, 2, 3, 4]); + + MatchArm::Arm(1) + }, + _ => MatchArm::Wild, + } +} + +fn main() { + let foo = vec![1, 2, 3, 4, 5]; + + assert_eq!(test(&foo), MatchArm::Arm(0)); + assert_eq!(test(&foo[..4]), MatchArm::Arm(1)); + assert_eq!(test(&foo[0..1]), MatchArm::Wild); +} diff --git a/src/test/ui/pattern/pat-tuple-bad-type.stderr b/src/test/ui/pattern/pat-tuple-bad-type.stderr index 95cca38f7de..598b6a3794e 100644 --- a/src/test/ui/pattern/pat-tuple-bad-type.stderr +++ b/src/test/ui/pattern/pat-tuple-bad-type.stderr @@ -12,6 +12,8 @@ LL | (..) => {} error[E0308]: mismatched types --> $DIR/pat-tuple-bad-type.rs:10:9 | +LL | match 0u8 { + | --- this expression has type `u8` LL | (..) => {} | ^^^^ expected `u8`, found `()` diff --git a/src/test/ui/pattern/pat-tuple-overfield.stderr b/src/test/ui/pattern/pat-tuple-overfield.stderr index 25d02b8627c..45b6fd1b4d4 100644 --- a/src/test/ui/pattern/pat-tuple-overfield.stderr +++ b/src/test/ui/pattern/pat-tuple-overfield.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/pat-tuple-overfield.rs:5:9 | +LL | match (1, 2, 3) { + | --------- this expression has type `({integer}, {integer}, {integer})` LL | (1, 2, 3, 4) => {} | ^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements | @@ -10,6 +12,9 @@ LL | (1, 2, 3, 4) => {} error[E0308]: mismatched types --> $DIR/pat-tuple-overfield.rs:6:9 | +LL | match (1, 2, 3) { + | --------- this expression has type `({integer}, {integer}, {integer})` +LL | (1, 2, 3, 4) => {} LL | (1, 2, .., 3, 4) => {} | ^^^^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements | diff --git a/src/test/ui/pattern/pattern-ident-path-generics.stderr b/src/test/ui/pattern/pattern-ident-path-generics.stderr index 338eb6ff0c8..24b5cdf98d5 100644 --- a/src/test/ui/pattern/pattern-ident-path-generics.stderr +++ b/src/test/ui/pattern/pattern-ident-path-generics.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/pattern-ident-path-generics.rs:3:9 | +LL | match Some("foo") { + | ----------- this expression has type `std::option::Option<&str>` LL | None:: => {} | ^^^^^^^^^^^^^ expected `&str`, found `isize` | diff --git a/src/test/ui/pattern/pattern-tyvar-2.stderr b/src/test/ui/pattern/pattern-tyvar-2.stderr index bb3e61017d4..95662444640 100644 --- a/src/test/ui/pattern/pattern-tyvar-2.stderr +++ b/src/test/ui/pattern/pattern-tyvar-2.stderr @@ -5,8 +5,6 @@ LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; | - ^ - {integer} | | | std::vec::Vec - | - = note: an implementation of `std::ops::Mul` might be missing for `std::vec::Vec` error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs index 11eae2af9c9..7d1cac8a442 100644 --- a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs +++ b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.rs @@ -21,7 +21,7 @@ fn uninhab_union() -> Foo { fn match_on_uninhab() { match uninhab_ref() { - //~^ ERROR non-exhaustive patterns: type `&'static !` is non-empty + //~^ ERROR non-exhaustive patterns: type `&!` is non-empty } match uninhab_union() { diff --git a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr index 1b1096c977a..e1079f912d0 100644 --- a/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr +++ b/src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr @@ -1,4 +1,4 @@ -error[E0004]: non-exhaustive patterns: type `&'static !` is non-empty +error[E0004]: non-exhaustive patterns: type `&!` is non-empty --> $DIR/always-inhabited-union-ref.rs:23:11 | LL | match uninhab_ref() { diff --git a/src/test/ui/privacy/associated-item-privacy-trait.rs b/src/test/ui/privacy/associated-item-privacy-trait.rs index b3d42f09596..03347d5b99a 100644 --- a/src/test/ui/privacy/associated-item-privacy-trait.rs +++ b/src/test/ui/privacy/associated-item-privacy-trait.rs @@ -23,8 +23,7 @@ mod priv_trait { ::CONST; //~^ ERROR associated constant `PrivTr::CONST` is private let _: ::AssocTy; - //~^ ERROR trait `priv_trait::PrivTr` is private - //~| ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR associated type `PrivTr::AssocTy` is private pub type InSignatureTy = ::AssocTy; //~^ ERROR trait `priv_trait::PrivTr` is private pub trait InSignatureTr: PrivTr {} @@ -116,15 +115,11 @@ mod priv_parent_substs { >::CONST; //~^ ERROR type `priv_parent_substs::Priv` is private - let _: ::AssocTy; - //~^ ERROR type `priv_parent_substs::Priv` is private - //~| ERROR type `priv_parent_substs::Priv` is private + let _: ::AssocTy; // FIXME no longer an error?! let _: >::AssocTy; //~^ ERROR type `priv_parent_substs::Priv` is private - //~| ERROR type `priv_parent_substs::Priv` is private let _: >::AssocTy; //~^ ERROR type `priv_parent_substs::Priv` is private - //~| ERROR type `priv_parent_substs::Priv` is private pub type InSignatureTy1 = ::AssocTy; //~^ ERROR type `priv_parent_substs::Priv` is private diff --git a/src/test/ui/privacy/associated-item-privacy-trait.stderr b/src/test/ui/privacy/associated-item-privacy-trait.stderr index ac422e99855..db24e425a01 100644 --- a/src/test/ui/privacy/associated-item-privacy-trait.stderr +++ b/src/test/ui/privacy/associated-item-privacy-trait.stderr @@ -42,18 +42,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private - --> $DIR/associated-item-privacy-trait.rs:25:13 - | -LL | let _: ::AssocTy; - | ^ -... -LL | priv_trait::mac!(); - | ------------------- in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: trait `priv_trait::PrivTr` is private +error: associated type `PrivTr::AssocTy` is private --> $DIR/associated-item-privacy-trait.rs:25:16 | LL | let _: ::AssocTy; @@ -65,7 +54,7 @@ LL | priv_trait::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: trait `priv_trait::PrivTr` is private - --> $DIR/associated-item-privacy-trait.rs:28:34 + --> $DIR/associated-item-privacy-trait.rs:27:34 | LL | pub type InSignatureTy = ::AssocTy; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,7 +65,7 @@ LL | priv_trait::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: trait `priv_trait::PrivTr` is private - --> $DIR/associated-item-privacy-trait.rs:30:34 + --> $DIR/associated-item-privacy-trait.rs:29:34 | LL | pub trait InSignatureTr: PrivTr {} | ^^^^^^ @@ -87,7 +76,7 @@ LL | priv_trait::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: trait `priv_trait::PrivTr` is private - --> $DIR/associated-item-privacy-trait.rs:32:14 + --> $DIR/associated-item-privacy-trait.rs:31:14 | LL | impl PrivTr for u8 {} | ^^^^^^ @@ -98,7 +87,7 @@ LL | priv_trait::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_signature::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:49:21 + --> $DIR/associated-item-privacy-trait.rs:48:21 | LL | let value = ::method; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +98,7 @@ LL | priv_signature::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_signature::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:51:9 + --> $DIR/associated-item-privacy-trait.rs:50:9 | LL | value; | ^^^^^ @@ -120,7 +109,7 @@ LL | priv_signature::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_signature::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:53:13 + --> $DIR/associated-item-privacy-trait.rs:52:13 | LL | Pub.method(loop {}); | ^^^^^^ @@ -131,7 +120,7 @@ LL | priv_signature::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:70:21 + --> $DIR/associated-item-privacy-trait.rs:69:21 | LL | let value = ::method::; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -142,7 +131,7 @@ LL | priv_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:72:9 + --> $DIR/associated-item-privacy-trait.rs:71:9 | LL | value; | ^^^^^ @@ -153,7 +142,7 @@ LL | priv_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:74:9 + --> $DIR/associated-item-privacy-trait.rs:73:9 | LL | Pub.method::(); | ^^^^^^^^^^^^^^^^^^^^ @@ -164,7 +153,7 @@ LL | priv_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:94:21 + --> $DIR/associated-item-privacy-trait.rs:93:21 | LL | let value = ::method; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -175,7 +164,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:96:9 + --> $DIR/associated-item-privacy-trait.rs:95:9 | LL | value; | ^^^^^ @@ -186,7 +175,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:98:21 + --> $DIR/associated-item-privacy-trait.rs:97:21 | LL | let value = >::method; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +186,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:100:9 + --> $DIR/associated-item-privacy-trait.rs:99:9 | LL | value; | ^^^^^ @@ -208,7 +197,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:102:9 + --> $DIR/associated-item-privacy-trait.rs:101:9 | LL | Pub.method(); | ^^^^^^^^^^^^ @@ -219,7 +208,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:105:21 + --> $DIR/associated-item-privacy-trait.rs:104:21 | LL | let value = >::method; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -230,7 +219,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:107:9 + --> $DIR/associated-item-privacy-trait.rs:106:9 | LL | value; | ^^^^^ @@ -241,7 +230,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:109:9 + --> $DIR/associated-item-privacy-trait.rs:108:9 | LL | Priv.method(); | ^^^^^^^^^^^^^ @@ -252,7 +241,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:112:9 + --> $DIR/associated-item-privacy-trait.rs:111:9 | LL | ::CONST; | ^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +252,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:114:9 + --> $DIR/associated-item-privacy-trait.rs:113:9 | LL | >::CONST; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -274,7 +263,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:116:9 + --> $DIR/associated-item-privacy-trait.rs:115:9 | LL | >::CONST; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -285,54 +274,10 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:119:13 - | -LL | let _: ::AssocTy; - | ^ -... -LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:119:16 - | -LL | let _: ::AssocTy; - | ^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:122:13 - | -LL | let _: >::AssocTy; - | ^ -... -LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:122:16 + --> $DIR/associated-item-privacy-trait.rs:119:30 | LL | let _: >::AssocTy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | priv_parent_substs::mac!(); - | --------------------------- in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:125:13 - | -LL | let _: >::AssocTy; - | ^ + | ^ ... LL | priv_parent_substs::mac!(); | --------------------------- in this macro invocation @@ -340,10 +285,10 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:125:16 + --> $DIR/associated-item-privacy-trait.rs:121:17 | LL | let _: >::AssocTy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ ... LL | priv_parent_substs::mac!(); | --------------------------- in this macro invocation @@ -351,7 +296,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:129:35 + --> $DIR/associated-item-privacy-trait.rs:124:35 | LL | pub type InSignatureTy1 = ::AssocTy; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -362,7 +307,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:131:35 + --> $DIR/associated-item-privacy-trait.rs:126:35 | LL | pub type InSignatureTy2 = >::AssocTy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +318,7 @@ LL | priv_parent_substs::mac!(); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: type `priv_parent_substs::Priv` is private - --> $DIR/associated-item-privacy-trait.rs:133:14 + --> $DIR/associated-item-privacy-trait.rs:128:14 | LL | impl PubTr for u8 {} | ^^^^^ @@ -383,5 +328,5 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 35 previous errors +error: aborting due to 30 previous errors diff --git a/src/test/ui/privacy/privacy1.rs b/src/test/ui/privacy/privacy1.rs index fcf7b19572f..e28fd13b97f 100644 --- a/src/test/ui/privacy/privacy1.rs +++ b/src/test/ui/privacy/privacy1.rs @@ -74,7 +74,7 @@ mod bar { } self::baz::A; self::baz::A::foo(); - self::baz::A::bar(); //~ ERROR: method `bar` is private + self::baz::A::bar(); //~ ERROR: associated function `bar` is private self::baz::A.foo2(); // this used to cause an ICE in privacy traversal. @@ -92,21 +92,21 @@ pub fn gpub() {} fn lol() { bar::A; bar::A::foo(); - bar::A::bar(); //~ ERROR: method `bar` is private + bar::A::bar(); //~ ERROR: associated function `bar` is private bar::A.foo2(); } mod foo { fn test() { ::bar::A::foo(); - ::bar::A::bar(); //~ ERROR: method `bar` is private + ::bar::A::bar(); //~ ERROR: associated function `bar` is private ::bar::A.foo2(); ::bar::baz::A::foo(); //~ ERROR: module `baz` is private ::bar::baz::A::bar(); //~ ERROR: module `baz` is private - //~^ ERROR: method `bar` is private + //~^ ERROR: associated function `bar` is private ::bar::baz::A.foo2(); //~ ERROR: module `baz` is private ::bar::baz::A.bar2(); //~ ERROR: module `baz` is private - //~^ ERROR: method `bar2` is private + //~^ ERROR: associated function `bar2` is private let _: isize = ::bar::B::foo(); //~ ERROR: trait `B` is private diff --git a/src/test/ui/privacy/privacy1.stderr b/src/test/ui/privacy/privacy1.stderr index 215df0dc754..ec2bc0d84ac 100644 --- a/src/test/ui/privacy/privacy1.stderr +++ b/src/test/ui/privacy/privacy1.stderr @@ -154,31 +154,31 @@ note: the trait `B` is defined here LL | trait B { | ^^^^^^^ -error[E0624]: method `bar` is private +error[E0624]: associated function `bar` is private --> $DIR/privacy1.rs:77:9 | LL | self::baz::A::bar(); | ^^^^^^^^^^^^^^^^^ -error[E0624]: method `bar` is private +error[E0624]: associated function `bar` is private --> $DIR/privacy1.rs:95:5 | LL | bar::A::bar(); | ^^^^^^^^^^^ -error[E0624]: method `bar` is private +error[E0624]: associated function `bar` is private --> $DIR/privacy1.rs:102:9 | LL | ::bar::A::bar(); | ^^^^^^^^^^^^^ -error[E0624]: method `bar` is private +error[E0624]: associated function `bar` is private --> $DIR/privacy1.rs:105:9 | LL | ::bar::baz::A::bar(); | ^^^^^^^^^^^^^^^^^^ -error[E0624]: method `bar2` is private +error[E0624]: associated function `bar2` is private --> $DIR/privacy1.rs:108:23 | LL | ::bar::baz::A.bar2(); diff --git a/src/test/ui/privacy/privacy2.stderr b/src/test/ui/privacy/privacy2.stderr index 719dc27ccf4..b10c3a52659 100644 --- a/src/test/ui/privacy/privacy2.stderr +++ b/src/test/ui/privacy/privacy2.stderr @@ -10,11 +10,16 @@ error[E0603]: function import `foo` is private LL | use bar::glob::foo; | ^^^ this function import is private | -note: the function import `foo` is defined here +note: the function import `foo` is defined here... --> $DIR/privacy2.rs:10:13 | LL | use foo; | ^^^ +note: ...and refers to the function `foo` which is defined here + --> $DIR/privacy2.rs:14:1 + | +LL | pub fn foo() {} + | ^^^^^^^^^^^^ consider importing it directly error: requires `sized` lang_item diff --git a/src/test/ui/privacy/private-impl-method.rs b/src/test/ui/privacy/private-impl-method.rs index b5587920f1c..f7be6726c5e 100644 --- a/src/test/ui/privacy/private-impl-method.rs +++ b/src/test/ui/privacy/private-impl-method.rs @@ -17,5 +17,5 @@ fn f() { fn main() { let s = a::Foo { x: 1 }; s.bar(); - s.foo(); //~ ERROR method `foo` is private + s.foo(); //~ ERROR associated function `foo` is private } diff --git a/src/test/ui/privacy/private-impl-method.stderr b/src/test/ui/privacy/private-impl-method.stderr index e1da3f47a4e..6833cdb4df9 100644 --- a/src/test/ui/privacy/private-impl-method.stderr +++ b/src/test/ui/privacy/private-impl-method.stderr @@ -1,4 +1,4 @@ -error[E0624]: method `foo` is private +error[E0624]: associated function `foo` is private --> $DIR/private-impl-method.rs:20:7 | LL | s.foo(); diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.rs b/src/test/ui/privacy/private-in-public-assoc-ty.rs index ad1052ada60..62faae1f399 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.rs +++ b/src/test/ui/privacy/private-in-public-assoc-ty.rs @@ -10,6 +10,11 @@ mod m { impl PrivTr for Priv {} pub trait PubTrAux1 {} pub trait PubTrAux2 { type A; } + impl PubTrAux1 for u8 {} + impl PubTrAux2 for u8 { + type A = Priv; + //~^ ERROR private type `m::Priv` in public interface + } // "Private-in-public in associated types is hard error" in RFC 2145 // applies only to the aliased types, not bounds. diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.stderr b/src/test/ui/privacy/private-in-public-assoc-ty.stderr index 3cc551cdede..c57073a004d 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.stderr +++ b/src/test/ui/privacy/private-in-public-assoc-ty.stderr @@ -1,5 +1,14 @@ +error[E0446]: private type `m::Priv` in public interface + --> $DIR/private-in-public-assoc-ty.rs:15:9 + | +LL | struct Priv; + | - `m::Priv` declared as private +... +LL | type A = Priv; + | ^^^^^^^^^^^^^^ can't leak private type + warning: private trait `m::PrivTr` in public interface (error E0445) - --> $DIR/private-in-public-assoc-ty.rs:16:5 + --> $DIR/private-in-public-assoc-ty.rs:21:5 | LL | / pub trait PubTr { LL | | @@ -15,7 +24,7 @@ LL | | } = note: for more information, see issue #34537 warning: private type `m::Priv` in public interface (error E0446) - --> $DIR/private-in-public-assoc-ty.rs:16:5 + --> $DIR/private-in-public-assoc-ty.rs:21:5 | LL | / pub trait PubTr { LL | | @@ -30,7 +39,7 @@ LL | | } = note: for more information, see issue #34537 warning: private type `m::Priv` in public interface (error E0446) - --> $DIR/private-in-public-assoc-ty.rs:16:5 + --> $DIR/private-in-public-assoc-ty.rs:21:5 | LL | / pub trait PubTr { LL | | @@ -45,7 +54,7 @@ LL | | } = note: for more information, see issue #34537 error[E0446]: private type `m::Priv` in public interface - --> $DIR/private-in-public-assoc-ty.rs:27:9 + --> $DIR/private-in-public-assoc-ty.rs:32:9 | LL | struct Priv; | - `m::Priv` declared as private @@ -54,7 +63,7 @@ LL | type Alias4 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `m::Priv` in public interface - --> $DIR/private-in-public-assoc-ty.rs:34:9 + --> $DIR/private-in-public-assoc-ty.rs:39:9 | LL | struct Priv; | - `m::Priv` declared as private @@ -63,7 +72,7 @@ LL | type Alias1 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0445]: private trait `m::PrivTr` in public interface - --> $DIR/private-in-public-assoc-ty.rs:37:9 + --> $DIR/private-in-public-assoc-ty.rs:42:9 | LL | trait PrivTr {} | - `m::PrivTr` declared as private @@ -72,7 +81,7 @@ LL | type Exist = impl PrivTr; | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait error[E0445]: private trait `m::PrivTr` in public interface - --> $DIR/private-in-public-assoc-ty.rs:37:9 + --> $DIR/private-in-public-assoc-ty.rs:42:9 | LL | trait PrivTr {} | - `m::PrivTr` declared as private @@ -80,7 +89,7 @@ LL | trait PrivTr {} LL | type Exist = impl PrivTr; | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0445, E0446. For more information about an error, try `rustc --explain E0445`. diff --git a/src/test/ui/privacy/private-method-cross-crate.rs b/src/test/ui/privacy/private-method-cross-crate.rs index 4da44e0682b..ab3bbdfe496 100644 --- a/src/test/ui/privacy/private-method-cross-crate.rs +++ b/src/test/ui/privacy/private-method-cross-crate.rs @@ -4,5 +4,5 @@ use cci_class_5::kitties::cat; fn main() { let nyan : cat = cat(52, 99); - nyan.nap(); //~ ERROR method `nap` is private + nyan.nap(); //~ ERROR associated function `nap` is private } diff --git a/src/test/ui/privacy/private-method-cross-crate.stderr b/src/test/ui/privacy/private-method-cross-crate.stderr index 10e0bfe5b13..6b49063815a 100644 --- a/src/test/ui/privacy/private-method-cross-crate.stderr +++ b/src/test/ui/privacy/private-method-cross-crate.stderr @@ -1,4 +1,4 @@ -error[E0624]: method `nap` is private +error[E0624]: associated function `nap` is private --> $DIR/private-method-cross-crate.rs:7:8 | LL | nyan.nap(); diff --git a/src/test/ui/privacy/private-method-inherited.rs b/src/test/ui/privacy/private-method-inherited.rs index bc27027e886..2f6454288ae 100644 --- a/src/test/ui/privacy/private-method-inherited.rs +++ b/src/test/ui/privacy/private-method-inherited.rs @@ -10,5 +10,5 @@ mod a { fn main() { let x = a::Foo; - x.f(); //~ ERROR method `f` is private + x.f(); //~ ERROR associated function `f` is private } diff --git a/src/test/ui/privacy/private-method-inherited.stderr b/src/test/ui/privacy/private-method-inherited.stderr index d2ba591ef0c..5551e1bd759 100644 --- a/src/test/ui/privacy/private-method-inherited.stderr +++ b/src/test/ui/privacy/private-method-inherited.stderr @@ -1,4 +1,4 @@ -error[E0624]: method `f` is private +error[E0624]: associated function `f` is private --> $DIR/private-method-inherited.rs:13:7 | LL | x.f(); diff --git a/src/test/ui/privacy/private-method.rs b/src/test/ui/privacy/private-method.rs index a9bea520e75..76a642cde1a 100644 --- a/src/test/ui/privacy/private-method.rs +++ b/src/test/ui/privacy/private-method.rs @@ -19,5 +19,5 @@ mod kitties { fn main() { let nyan : kitties::Cat = kitties::cat(52, 99); - nyan.nap(); //~ ERROR method `nap` is private + nyan.nap(); //~ ERROR associated function `nap` is private } diff --git a/src/test/ui/privacy/private-method.stderr b/src/test/ui/privacy/private-method.stderr index 61fc122e318..583dc123e24 100644 --- a/src/test/ui/privacy/private-method.stderr +++ b/src/test/ui/privacy/private-method.stderr @@ -1,4 +1,4 @@ -error[E0624]: method `nap` is private +error[E0624]: associated function `nap` is private --> $DIR/private-method.rs:22:8 | LL | nyan.nap(); diff --git a/src/test/ui/privacy/restricted/test.stderr b/src/test/ui/privacy/restricted/test.stderr index aac444b8e3c..e73f723ed0a 100644 --- a/src/test/ui/privacy/restricted/test.stderr +++ b/src/test/ui/privacy/restricted/test.stderr @@ -52,13 +52,13 @@ error[E0616]: field `x` of struct `foo::bar::S` is private LL | S::default().x; | ^^^^^^^^^^^^^^ -error[E0624]: method `f` is private +error[E0624]: associated function `f` is private --> $DIR/test.rs:32:18 | LL | S::default().f(); | ^ -error[E0624]: method `g` is private +error[E0624]: associated function `g` is private --> $DIR/test.rs:33:5 | LL | S::g(); @@ -76,13 +76,13 @@ error[E0616]: field `z` of struct `pub_restricted::Universe` is private LL | let _ = u.z; | ^^^ -error[E0624]: method `g` is private +error[E0624]: associated function `g` is private --> $DIR/test.rs:45:7 | LL | u.g(); | ^ -error[E0624]: method `h` is private +error[E0624]: associated function `h` is private --> $DIR/test.rs:46:7 | LL | u.h(); diff --git a/src/test/ui/proc-macro/attribute-spans-preserved.stdout b/src/test/ui/proc-macro/attribute-spans-preserved.stdout index faf31712156..cf9a97491f0 100644 --- a/src/test/ui/proc-macro/attribute-spans-preserved.stdout +++ b/src/test/ui/proc-macro/attribute-spans-preserved.stdout @@ -1 +1 @@ -fn main () { let y : u32 = "z" ; { let x : u32 = "y" ; } } +fn main() { let y : u32 = "z" ; { let x : u32 = "y" ; } } diff --git a/src/test/ui/proc-macro/auxiliary/derive-unstable.rs b/src/test/ui/proc-macro/auxiliary/derive-unstable.rs index f702df66db1..2ccd3f88200 100644 --- a/src/test/ui/proc-macro/auxiliary/derive-unstable.rs +++ b/src/test/ui/proc-macro/auxiliary/derive-unstable.rs @@ -10,5 +10,5 @@ use proc_macro::TokenStream; #[proc_macro_derive(Unstable)] pub fn derive(_input: TokenStream) -> TokenStream { - "unsafe fn foo() -> u32 { ::std::intrinsics::init() }".parse().unwrap() + "unsafe fn foo() -> u32 { ::std::intrinsics::abort() }".parse().unwrap() } diff --git a/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs b/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs new file mode 100644 index 00000000000..c9f0664c3a3 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/generate-dollar-ident.rs @@ -0,0 +1,17 @@ +// force-host +// no-prefer-dynamic + +#![feature(proc_macro_hygiene)] +#![feature(proc_macro_quote)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro] +pub fn dollar_ident(input: TokenStream) -> TokenStream { + let black_hole = input.into_iter().next().unwrap(); + quote! { + $black_hole!($$var); + } +} diff --git a/src/test/ui/proc-macro/crt-static.rs b/src/test/ui/proc-macro/crt-static.rs new file mode 100644 index 00000000000..90e3d422b3c --- /dev/null +++ b/src/test/ui/proc-macro/crt-static.rs @@ -0,0 +1,16 @@ +// Test proc-macro crate can be built without addtional RUSTFLAGS +// on musl target +// override -Ctarget-feature=-crt-static from compiletest +// compile-flags: -Ctarget-feature= +// ignore-wasm32 +// build-pass +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(Foo)] +pub fn derive_foo(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout index ea06f6c1aca..15433bebde9 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout @@ -1,4 +1,4 @@ -PRINT-BANG INPUT (DISPLAY): struct M ($crate :: S) ; +PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -39,7 +39,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): struct A(crate::S); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ($crate :: S) ; +PRINT-ATTR RE-COLLECTED (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", diff --git a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout index 619b2fd5321..73e407918ec 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout @@ -1,5 +1,5 @@ PRINT-ATTR INPUT (DISPLAY): struct A(identity!(crate :: S)); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A (identity ! ($crate :: S)) ; +PRINT-ATTR RE-COLLECTED (DISPLAY): struct A(identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -55,7 +55,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): struct B(identity!(::dollar_crate_external :: S)); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct B (identity ! ($crate :: S)) ; +PRINT-ATTR RE-COLLECTED (DISPLAY): struct B(identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout index 5fdc6f8ee96..e125a3e7f17 100644 --- a/src/test/ui/proc-macro/dollar-crate.stdout +++ b/src/test/ui/proc-macro/dollar-crate.stdout @@ -1,4 +1,4 @@ -PRINT-BANG INPUT (DISPLAY): struct M ($crate :: S) ; +PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -39,7 +39,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): struct A(crate::S); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ($crate :: S) ; +PRINT-ATTR RE-COLLECTED (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -80,7 +80,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): struct D(crate::S); -PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ($crate :: S) ; +PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -120,7 +120,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: #3 bytes(LO..HI), }, ] -PRINT-BANG INPUT (DISPLAY): struct M ($crate :: S) ; +PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -161,7 +161,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ }, ] PRINT-ATTR INPUT (DISPLAY): struct A(::dollar_crate_external::S); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ($crate :: S) ; +PRINT-ATTR RE-COLLECTED (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -202,7 +202,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ }, ] PRINT-DERIVE INPUT (DISPLAY): struct D(::dollar_crate_external::S); -PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ($crate :: S) ; +PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", diff --git a/src/test/ui/proc-macro/expand-to-unstable-2.stderr b/src/test/ui/proc-macro/expand-to-unstable-2.stderr index ff2e3af3777..19144b210a1 100644 --- a/src/test/ui/proc-macro/expand-to-unstable-2.stderr +++ b/src/test/ui/proc-macro/expand-to-unstable-2.stderr @@ -4,7 +4,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[derive(Unstable)] | ^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/proc-macro/generate-dollar-ident.rs b/src/test/ui/proc-macro/generate-dollar-ident.rs new file mode 100644 index 00000000000..b838be9fb9f --- /dev/null +++ b/src/test/ui/proc-macro/generate-dollar-ident.rs @@ -0,0 +1,18 @@ +// Proc macros can generate token sequence `$ IDENT` +// without it being recognized as an unknown macro variable. + +// check-pass +// aux-build:generate-dollar-ident.rs + +extern crate generate_dollar_ident; +use generate_dollar_ident::*; + +macro_rules! black_hole { + ($($tt:tt)*) => {}; +} + +black_hole!($var); + +dollar_ident!(black_hole); + +fn main() {} diff --git a/src/test/ui/proc-macro/mixed-site-span.stderr b/src/test/ui/proc-macro/mixed-site-span.stderr index c344147ed93..30a4cd7c116 100644 --- a/src/test/ui/proc-macro/mixed-site-span.stderr +++ b/src/test/ui/proc-macro/mixed-site-span.stderr @@ -21,21 +21,10 @@ LL | local_def; | ^^^^^^^^^ not found in this scope error[E0412]: cannot find type `ItemUse` in crate `$crate` - --> $DIR/auxiliary/mixed-site-span.rs:14:1 - | -LL | / pub fn proc_macro_rules(input: TokenStream) -> TokenStream { -LL | | if input.is_empty() { -LL | | let id = |s| TokenTree::from(Ident::new(s, Span::mixed_site())); -LL | | let item_def = id("ItemDef"); -... | -LL | | } -LL | | } - | |_^ not found in `$crate` - | - ::: $DIR/mixed-site-span.rs:26:1 - | -LL | pass_dollar_crate!(); - | --------------------- in this macro invocation + --> $DIR/mixed-site-span.rs:26:1 + | +LL | pass_dollar_crate!(); + | ^^^^^^^^^^^^^^^^^^^^^ not found in `$crate` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: possible candidate is found in another module, you can import it into scope diff --git a/src/test/ui/proc-macro/multispan.stderr b/src/test/ui/proc-macro/multispan.stderr index c9390a04b9e..4405278528e 100644 --- a/src/test/ui/proc-macro/multispan.stderr +++ b/src/test/ui/proc-macro/multispan.stderr @@ -1,19 +1,8 @@ error: hello to you, too! - --> $DIR/auxiliary/multispan.rs:31:1 - | -LL | / pub fn hello(input: TokenStream) -> TokenStream { -LL | | if let Err(diag) = parse(input) { -LL | | diag.emit(); -LL | | } -LL | | -LL | | TokenStream::new() -LL | | } - | |_^ - | - ::: $DIR/multispan.rs:14:5 - | -LL | hello!(hi); - | ----------- in this macro invocation + --> $DIR/multispan.rs:14:5 + | +LL | hello!(hi); + | ^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:14:12 @@ -23,21 +12,10 @@ LL | hello!(hi); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: hello to you, too! - --> $DIR/auxiliary/multispan.rs:31:1 - | -LL | / pub fn hello(input: TokenStream) -> TokenStream { -LL | | if let Err(diag) = parse(input) { -LL | | diag.emit(); -LL | | } -LL | | -LL | | TokenStream::new() -LL | | } - | |_^ - | - ::: $DIR/multispan.rs:17:5 - | -LL | hello!(hi hi); - | -------------- in this macro invocation + --> $DIR/multispan.rs:17:5 + | +LL | hello!(hi hi); + | ^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:17:12 @@ -47,21 +25,10 @@ LL | hello!(hi hi); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: hello to you, too! - --> $DIR/auxiliary/multispan.rs:31:1 - | -LL | / pub fn hello(input: TokenStream) -> TokenStream { -LL | | if let Err(diag) = parse(input) { -LL | | diag.emit(); -LL | | } -LL | | -LL | | TokenStream::new() -LL | | } - | |_^ - | - ::: $DIR/multispan.rs:20:5 - | -LL | hello!(hi hi hi); - | ----------------- in this macro invocation + --> $DIR/multispan.rs:20:5 + | +LL | hello!(hi hi hi); + | ^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:20:12 @@ -71,21 +38,10 @@ LL | hello!(hi hi hi); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: hello to you, too! - --> $DIR/auxiliary/multispan.rs:31:1 - | -LL | / pub fn hello(input: TokenStream) -> TokenStream { -LL | | if let Err(diag) = parse(input) { -LL | | diag.emit(); -LL | | } -LL | | -LL | | TokenStream::new() -LL | | } - | |_^ - | - ::: $DIR/multispan.rs:23:5 - | -LL | hello!(hi hey hi yo hi beep beep hi hi); - | ---------------------------------------- in this macro invocation + --> $DIR/multispan.rs:23:5 + | +LL | hello!(hi hey hi yo hi beep beep hi hi); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:23:12 @@ -95,21 +51,10 @@ LL | hello!(hi hey hi yo hi beep beep hi hi); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: hello to you, too! - --> $DIR/auxiliary/multispan.rs:31:1 - | -LL | / pub fn hello(input: TokenStream) -> TokenStream { -LL | | if let Err(diag) = parse(input) { -LL | | diag.emit(); -LL | | } -LL | | -LL | | TokenStream::new() -LL | | } - | |_^ - | - ::: $DIR/multispan.rs:24:5 - | -LL | hello!(hi there, hi how are you? hi... hi.); - | -------------------------------------------- in this macro invocation + --> $DIR/multispan.rs:24:5 + | +LL | hello!(hi there, hi how are you? hi... hi.); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:24:12 @@ -119,21 +64,10 @@ LL | hello!(hi there, hi how are you? hi... hi.); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: hello to you, too! - --> $DIR/auxiliary/multispan.rs:31:1 - | -LL | / pub fn hello(input: TokenStream) -> TokenStream { -LL | | if let Err(diag) = parse(input) { -LL | | diag.emit(); -LL | | } -LL | | -LL | | TokenStream::new() -LL | | } - | |_^ - | - ::: $DIR/multispan.rs:25:5 - | -LL | hello!(whoah. hi di hi di ho); - | ------------------------------ in this macro invocation + --> $DIR/multispan.rs:25:5 + | +LL | hello!(whoah. hi di hi di ho); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:25:19 @@ -143,21 +77,10 @@ LL | hello!(whoah. hi di hi di ho); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: hello to you, too! - --> $DIR/auxiliary/multispan.rs:31:1 - | -LL | / pub fn hello(input: TokenStream) -> TokenStream { -LL | | if let Err(diag) = parse(input) { -LL | | diag.emit(); -LL | | } -LL | | -LL | | TokenStream::new() -LL | | } - | |_^ - | - ::: $DIR/multispan.rs:26:5 - | -LL | hello!(hi good hi and good bye); - | -------------------------------- in this macro invocation + --> $DIR/multispan.rs:26:5 + | +LL | hello!(hi good hi and good bye); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: found these 'hi's --> $DIR/multispan.rs:26:12 diff --git a/src/test/ui/proc-macro/span-api-tests.rs b/src/test/ui/proc-macro/span-api-tests.rs index 3667e14c9e0..5c0cbd77a8d 100644 --- a/src/test/ui/proc-macro/span-api-tests.rs +++ b/src/test/ui/proc-macro/span-api-tests.rs @@ -11,7 +11,9 @@ extern crate span_test_macros; extern crate span_api_tests; -use span_api_tests::{reemit, assert_fake_source_file, assert_source_file, macro_stringify}; +// FIXME(69775): Investigate `assert_fake_source_file`. + +use span_api_tests::{reemit, assert_source_file, macro_stringify}; macro_rules! say_hello { ($macname:ident) => ( $macname! { "Hello, world!" }) @@ -25,7 +27,7 @@ reemit_legacy! { assert_source_file! { "Hello, world!" } } -say_hello_extern! { assert_fake_source_file } +say_hello_extern! { assert_source_file } reemit! { assert_source_file! { "Hello, world!" } diff --git a/src/test/ui/proc-macro/three-equals.stderr b/src/test/ui/proc-macro/three-equals.stderr index 82c4167262f..ca82a345345 100644 --- a/src/test/ui/proc-macro/three-equals.stderr +++ b/src/test/ui/proc-macro/three-equals.stderr @@ -1,19 +1,8 @@ error: found 2 equal signs, need exactly 3 - --> $DIR/auxiliary/three-equals.rs:42:1 - | -LL | / pub fn three_equals(input: TokenStream) -> TokenStream { -LL | | if let Err(diag) = parse(input) { -LL | | diag.emit(); -LL | | return TokenStream::new(); -... | -LL | | "3".parse().unwrap() -LL | | } - | |_^ - | - ::: $DIR/three-equals.rs:15:5 - | -LL | three_equals!(==); - | ------------------ in this macro invocation + --> $DIR/three-equals.rs:15:5 + | +LL | three_equals!(==); + | ^^^^^^^^^^^^^^^^^^ | = help: input must be: `===` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/proc-macro/trait-fn-args-2015.rs b/src/test/ui/proc-macro/trait-fn-args-2015.rs new file mode 100644 index 00000000000..3a448d4b220 --- /dev/null +++ b/src/test/ui/proc-macro/trait-fn-args-2015.rs @@ -0,0 +1,14 @@ +// Unnamed arguments in trait functions can be passed through proc macros on 2015 edition. + +// check-pass +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +trait Tr { + #[identity_attr] + fn method(u8); +} + +fn main() {} diff --git a/src/test/ui/pub/pub-restricted-error-fn.rs b/src/test/ui/pub/pub-restricted-error-fn.rs index 56ee02f517c..fc1aeae2b0c 100644 --- a/src/test/ui/pub/pub-restricted-error-fn.rs +++ b/src/test/ui/pub/pub-restricted-error-fn.rs @@ -1,3 +1,2 @@ -#![feature(pub_restricted)] - -pub(crate) () fn foo() {} //~ unmatched visibility +pub(crate) () fn foo() {} //~ ERROR visibility `pub(crate)` is not followed by an item +//~^ ERROR expected item, found `(` diff --git a/src/test/ui/pub/pub-restricted-error-fn.stderr b/src/test/ui/pub/pub-restricted-error-fn.stderr index fcff5334890..0511a821a7a 100644 --- a/src/test/ui/pub/pub-restricted-error-fn.stderr +++ b/src/test/ui/pub/pub-restricted-error-fn.stderr @@ -1,8 +1,16 @@ -error: unmatched visibility `pub` - --> $DIR/pub-restricted-error-fn.rs:3:10 +error: visibility `pub(crate)` is not followed by an item + --> $DIR/pub-restricted-error-fn.rs:1:1 | LL | pub(crate) () fn foo() {} - | ^ + | ^^^^^^^^^^ the visibility + | + = help: you likely meant to define an item, e.g., `pub(crate) fn foo() {}` + +error: expected item, found `(` + --> $DIR/pub-restricted-error-fn.rs:1:12 + | +LL | pub(crate) () fn foo() {} + | ^ expected item -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/qualified/qualified-path-params.rs b/src/test/ui/qualified/qualified-path-params.rs index b1b60b4b73f..65549d909d0 100644 --- a/src/test/ui/qualified/qualified-path-params.rs +++ b/src/test/ui/qualified/qualified-path-params.rs @@ -18,7 +18,7 @@ impl S { fn main() { match 10 { ::A::f:: => {} - //~^ ERROR expected unit struct, unit variant or constant, found method `<::A>::f` + //~^ ERROR expected unit struct, unit variant or constant, found associated function 0 ..= ::A::f:: => {} //~ ERROR only char and numeric types are allowed in range } } diff --git a/src/test/ui/qualified/qualified-path-params.stderr b/src/test/ui/qualified/qualified-path-params.stderr index 7a74a37021b..7ff43f4404c 100644 --- a/src/test/ui/qualified/qualified-path-params.stderr +++ b/src/test/ui/qualified/qualified-path-params.stderr @@ -1,4 +1,4 @@ -error[E0533]: expected unit struct, unit variant or constant, found method `<::A>::f` +error[E0533]: expected unit struct, unit variant or constant, found associated function `<::A>::f` --> $DIR/qualified-path-params.rs:20:9 | LL | ::A::f:: => {} diff --git a/src/test/ui/range/issue-54505-no-std.rs b/src/test/ui/range/issue-54505-no-std.rs index 22cf15fb2e4..c6a3cc346fc 100644 --- a/src/test/ui/range/issue-54505-no-std.rs +++ b/src/test/ui/range/issue-54505-no-std.rs @@ -15,10 +15,6 @@ use core::ops::RangeBounds; #[lang = "eh_personality"] extern fn eh_personality() {} -#[cfg(target_os = "windows")] -#[lang = "eh_unwind_resume"] -extern fn eh_unwind_resume() {} - // take a reference to any built-in range fn take_range(_r: &impl RangeBounds) {} diff --git a/src/test/ui/range/issue-54505-no-std.stderr b/src/test/ui/range/issue-54505-no-std.stderr index aead80fa500..90934061132 100644 --- a/src/test/ui/range/issue-54505-no-std.stderr +++ b/src/test/ui/range/issue-54505-no-std.stderr @@ -1,7 +1,7 @@ error: `#[panic_handler]` function required, but not found error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:28:16 + --> $DIR/issue-54505-no-std.rs:24:16 | LL | take_range(0..1); | ^^^^ @@ -13,7 +13,7 @@ LL | take_range(0..1); found struct `core::ops::Range<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:33:16 + --> $DIR/issue-54505-no-std.rs:29:16 | LL | take_range(1..); | ^^^ @@ -25,7 +25,7 @@ LL | take_range(1..); found struct `core::ops::RangeFrom<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:38:16 + --> $DIR/issue-54505-no-std.rs:34:16 | LL | take_range(..); | ^^ @@ -37,7 +37,7 @@ LL | take_range(..); found struct `core::ops::RangeFull` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:43:16 + --> $DIR/issue-54505-no-std.rs:39:16 | LL | take_range(0..=1); | ^^^^^ @@ -49,7 +49,7 @@ LL | take_range(0..=1); found struct `core::ops::RangeInclusive<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:48:16 + --> $DIR/issue-54505-no-std.rs:44:16 | LL | take_range(..5); | ^^^ @@ -61,7 +61,7 @@ LL | take_range(..5); found struct `core::ops::RangeTo<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:53:16 + --> $DIR/issue-54505-no-std.rs:49:16 | LL | take_range(..=42); | ^^^^^ diff --git a/src/test/ui/realloc-16687.rs b/src/test/ui/realloc-16687.rs index 425aa83e70a..eb6224ad1bb 100644 --- a/src/test/ui/realloc-16687.rs +++ b/src/test/ui/realloc-16687.rs @@ -41,13 +41,13 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let (ptr, _) = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); if PRINT { - println!("allocate({:?}) = {:?}", layout, ret); + println!("allocate({:?}) = {:?}", layout, ptr); } - ret.cast().as_ptr() + ptr.cast().as_ptr() } unsafe fn deallocate(ptr: *mut u8, layout: Layout) { @@ -63,16 +63,16 @@ unsafe fn test_triangle() -> bool { println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new); } - let ret = Global.realloc(NonNull::new_unchecked(ptr), old, new.size()) + let (ptr, _) = Global.realloc(NonNull::new_unchecked(ptr), old, new.size()) .unwrap_or_else(|_| handle_alloc_error( Layout::from_size_align_unchecked(new.size(), old.align()) )); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", - ptr, old, new, ret); + ptr, old, new, ptr); } - ret.cast().as_ptr() + ptr.cast().as_ptr() } fn idx_to_size(i: usize) -> usize { (i+1) * 10 } diff --git a/src/test/ui/recursion_limit/empty.rs b/src/test/ui/recursion_limit/empty.rs new file mode 100644 index 00000000000..31ff9c1e3a7 --- /dev/null +++ b/src/test/ui/recursion_limit/empty.rs @@ -0,0 +1,6 @@ +// Test the parse error for an empty recursion_limit + +#![recursion_limit = ""] //~ ERROR `limit` must be a non-negative integer + //~| `limit` must be a non-negative integer + +fn main() {} diff --git a/src/test/ui/recursion_limit/empty.stderr b/src/test/ui/recursion_limit/empty.stderr new file mode 100644 index 00000000000..bcd1d27e59b --- /dev/null +++ b/src/test/ui/recursion_limit/empty.stderr @@ -0,0 +1,10 @@ +error: `limit` must be a non-negative integer + --> $DIR/empty.rs:3:1 + | +LL | #![recursion_limit = ""] + | ^^^^^^^^^^^^^^^^^^^^^--^ + | | + | `limit` must be a non-negative integer + +error: aborting due to previous error + diff --git a/src/test/ui/recursion_limit/invalid_digit.rs b/src/test/ui/recursion_limit/invalid_digit.rs new file mode 100644 index 00000000000..759d69d0af2 --- /dev/null +++ b/src/test/ui/recursion_limit/invalid_digit.rs @@ -0,0 +1,6 @@ +// Test the parse error for an invalid digit in recursion_limit + +#![recursion_limit = "-100"] //~ ERROR `limit` must be a non-negative integer + //~| not a valid integer + +fn main() {} diff --git a/src/test/ui/recursion_limit/invalid_digit.stderr b/src/test/ui/recursion_limit/invalid_digit.stderr new file mode 100644 index 00000000000..e6fd6b72a09 --- /dev/null +++ b/src/test/ui/recursion_limit/invalid_digit.stderr @@ -0,0 +1,10 @@ +error: `limit` must be a non-negative integer + --> $DIR/invalid_digit.rs:3:1 + | +LL | #![recursion_limit = "-100"] + | ^^^^^^^^^^^^^^^^^^^^^------^ + | | + | not a valid integer + +error: aborting due to previous error + diff --git a/src/test/ui/recursion_limit/overflow.rs b/src/test/ui/recursion_limit/overflow.rs new file mode 100644 index 00000000000..8eee2792b23 --- /dev/null +++ b/src/test/ui/recursion_limit/overflow.rs @@ -0,0 +1,7 @@ +// Test the parse error for an overflowing recursion_limit + +#![recursion_limit = "999999999999999999999999"] +//~^ ERROR `limit` must be a non-negative integer +//~| `limit` is too large + +fn main() {} diff --git a/src/test/ui/recursion_limit/overflow.stderr b/src/test/ui/recursion_limit/overflow.stderr new file mode 100644 index 00000000000..f6ed76c1ebc --- /dev/null +++ b/src/test/ui/recursion_limit/overflow.stderr @@ -0,0 +1,10 @@ +error: `limit` must be a non-negative integer + --> $DIR/overflow.rs:3:1 + | +LL | #![recursion_limit = "999999999999999999999999"] + | ^^^^^^^^^^^^^^^^^^^^^--------------------------^ + | | + | `limit` is too large + +error: aborting due to previous error + diff --git a/src/test/ui/recursion_limit/zero.rs b/src/test/ui/recursion_limit/zero.rs new file mode 100644 index 00000000000..eb95d7babc6 --- /dev/null +++ b/src/test/ui/recursion_limit/zero.rs @@ -0,0 +1,12 @@ +// Test that a `limit` of 0 is valid + +#![recursion_limit = "0"] + +macro_rules! test { + () => {}; + ($tt:tt) => { test!(); }; +} + +test!(test); //~ ERROR 10:1: 10:13: recursion limit reached while expanding `test!` + +fn main() {} diff --git a/src/test/ui/recursion_limit/zero.stderr b/src/test/ui/recursion_limit/zero.stderr new file mode 100644 index 00000000000..6358805d89d --- /dev/null +++ b/src/test/ui/recursion_limit/zero.stderr @@ -0,0 +1,10 @@ +error: recursion limit reached while expanding `test!` + --> $DIR/zero.rs:10:1 + | +LL | test!(test); + | ^^^^^^^^^^^^ + | + = help: consider adding a `#![recursion_limit="0"]` attribute to your crate (`zero`) + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-close-object-into-object-5.stderr b/src/test/ui/regions/regions-close-object-into-object-5.stderr index 7c530cec7c3..14727000b2c 100644 --- a/src/test/ui/regions/regions-close-object-into-object-5.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-5.stderr @@ -2,7 +2,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:5 | LL | fn f<'a, T, U>(v: Box+'static>) -> Box { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box | ^^^^^^^^^^ @@ -17,7 +17,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:5 | LL | fn f<'a, T, U>(v: Box+'static>) -> Box { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box | ^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:9 | LL | fn f<'a, T, U>(v: Box+'static>) -> Box { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box | ^ @@ -47,7 +47,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:9 | LL | fn f<'a, T, U>(v: Box+'static>) -> Box { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box | ^^^^^^ @@ -62,7 +62,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:11 | LL | fn f<'a, T, U>(v: Box+'static>) -> Box { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box | ^^^ @@ -77,7 +77,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:11 | LL | fn f<'a, T, U>(v: Box+'static>) -> Box { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box | ^^^ @@ -92,7 +92,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:11 | LL | fn f<'a, T, U>(v: Box+'static>) -> Box { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! LL | box B(&*v) as Box | ^^^ diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr index 81534b7b770..ed9a604e717 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr @@ -2,7 +2,7 @@ error[E0310]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:10:5 | LL | fn make_object1(v: A) -> Box { - | -- help: consider adding an explicit lifetime bound `A: 'static`... + | -- help: consider adding an explicit lifetime bound...: `A: 'static +` LL | box v as Box | ^^^^^ | @@ -16,7 +16,7 @@ error[E0310]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:10:5 | LL | fn make_object1(v: A) -> Box { - | -- help: consider adding an explicit lifetime bound `A: 'static`... + | -- help: consider adding an explicit lifetime bound...: `A: 'static +` LL | box v as Box | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -30,7 +30,7 @@ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:20:5 | LL | fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { - | -- help: consider adding an explicit lifetime bound `A: 'b`... + | -- help: consider adding an explicit lifetime bound...: `A: 'b +` LL | box v as Box | ^^^^^ | @@ -44,7 +44,7 @@ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:20:5 | LL | fn make_object3<'a,'b,A:SomeTrait+'a>(v: A) -> Box { - | -- help: consider adding an explicit lifetime bound `A: 'b`... + | -- help: consider adding an explicit lifetime bound...: `A: 'b +` LL | box v as Box | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/src/test/ui/regions/regions-close-param-into-object.stderr b/src/test/ui/regions/regions-close-param-into-object.stderr index 7f2c646c121..3b1a89d9ced 100644 --- a/src/test/ui/regions/regions-close-param-into-object.stderr +++ b/src/test/ui/regions/regions-close-param-into-object.stderr @@ -2,7 +2,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:6:5 | LL | fn p1(v: T) -> Box - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` ... LL | Box::new(v) | ^^^^^^^^^^^ @@ -17,7 +17,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:12:5 | LL | fn p2(v: Box) -> Box - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` ... LL | Box::new(v) | ^^^^^^^^^^^ @@ -32,7 +32,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:18:5 | LL | fn p3<'a,T>(v: T) -> Box - | - help: consider adding an explicit lifetime bound `T: 'a`... + | - help: consider adding an explicit lifetime bound...: `T: 'a` ... LL | Box::new(v) | ^^^^^^^^^^^ @@ -47,7 +47,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:24:5 | LL | fn p4<'a,T>(v: Box) -> Box - | - help: consider adding an explicit lifetime bound `T: 'a`... + | - help: consider adding an explicit lifetime bound...: `T: 'a` ... LL | Box::new(v) | ^^^^^^^^^^^ diff --git a/src/test/ui/regions/regions-enum-not-wf.stderr b/src/test/ui/regions/regions-enum-not-wf.stderr index 87014085667..297fcb088d2 100644 --- a/src/test/ui/regions/regions-enum-not-wf.stderr +++ b/src/test/ui/regions/regions-enum-not-wf.stderr @@ -2,7 +2,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:18:18 | LL | enum Ref1<'a, T> { - | - help: consider adding an explicit lifetime bound `T: 'a`... + | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | Ref1Variant1(RequireOutlives<'a, T>) | ^^^^^^^^^^^^^^^^^^^^^^ | @@ -16,7 +16,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:23:25 | LL | enum Ref2<'a, T> { - | - help: consider adding an explicit lifetime bound `T: 'a`... + | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | Ref2Variant1, LL | Ref2Variant2(isize, RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:35:1 | LL | enum RefDouble<'a, 'b, T> { - | ^ - help: consider adding an explicit lifetime bound `T: 'b`... + | ^ - help: consider adding an explicit lifetime bound...: `T: 'b` | _| | | LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) @@ -52,7 +52,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:36:23 | LL | enum RefDouble<'a, 'b, T> { - | - help: consider adding an explicit lifetime bound `T: 'b`... + | - help: consider adding an explicit lifetime bound...: `T: 'b` LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr index a33d3583552..06e1b0f1ac2 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller.migrate.stderr @@ -1,32 +1,54 @@ -error[E0623]: lifetime mismatch +error[E0491]: in type `&'b &'a usize`, reference has a longer lifetime than the data it references --> $DIR/regions-free-region-ordering-caller.rs:11:12 | -LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { - | --------- --------- - | | - | these two types are declared with different lifetimes... LL | let z: Option<&'b &'a usize> = None; - | ^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime `'b` as defined on the function body at 10:14 + --> $DIR/regions-free-region-ordering-caller.rs:10:14 + | +LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { + | ^^ +note: but the referenced data is only valid for the lifetime `'a` as defined on the function body at 10:10 + --> $DIR/regions-free-region-ordering-caller.rs:10:10 + | +LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { + | ^^ -error[E0623]: lifetime mismatch +error[E0491]: in type `&'b Paramd<'a>`, reference has a longer lifetime than the data it references --> $DIR/regions-free-region-ordering-caller.rs:17:12 | -LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { - | --------- --------- - | | - | these two types are declared with different lifetimes... -LL | let y: Paramd<'a> = Paramd { x: a }; LL | let z: Option<&'b Paramd<'a>> = None; - | ^^^^^^^^^^^^^^^^^^^^^^ ...but data from `a` flows into `b` here + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime `'b` as defined on the function body at 15:14 + --> $DIR/regions-free-region-ordering-caller.rs:15:14 + | +LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { + | ^^ +note: but the referenced data is only valid for the lifetime `'a` as defined on the function body at 15:10 + --> $DIR/regions-free-region-ordering-caller.rs:15:10 + | +LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { + | ^^ -error[E0623]: lifetime mismatch +error[E0491]: in type `&'a &'b usize`, reference has a longer lifetime than the data it references --> $DIR/regions-free-region-ordering-caller.rs:22:12 | -LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { - | --------- --------- these two types are declared with different lifetimes... LL | let z: Option<&'a &'b usize> = None; - | ^^^^^^^^^^^^^^^^^^^^^ ...but data from `b` flows into `a` here + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime `'a` as defined on the function body at 21:10 + --> $DIR/regions-free-region-ordering-caller.rs:21:10 + | +LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { + | ^^ +note: but the referenced data is only valid for the lifetime `'b` as defined on the function body at 21:14 + --> $DIR/regions-free-region-ordering-caller.rs:21:14 + | +LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { + | ^^ error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0623`. +For more information about this error, try `rustc --explain E0491`. diff --git a/src/test/ui/regions/regions-free-region-ordering-caller.rs b/src/test/ui/regions/regions-free-region-ordering-caller.rs index c0b12f23cdb..2bf4734cf73 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller.rs +++ b/src/test/ui/regions/regions-free-region-ordering-caller.rs @@ -8,18 +8,18 @@ struct Paramd<'a> { x: &'a usize } fn call2<'a, 'b>(a: &'a usize, b: &'b usize) { - let z: Option<&'b &'a usize> = None;//[migrate]~ ERROR E0623 + let z: Option<&'b &'a usize> = None;//[migrate]~ ERROR E0491 //[nll]~^ ERROR lifetime may not live long enough } fn call3<'a, 'b>(a: &'a usize, b: &'b usize) { let y: Paramd<'a> = Paramd { x: a }; - let z: Option<&'b Paramd<'a>> = None;//[migrate]~ ERROR E0623 + let z: Option<&'b Paramd<'a>> = None;//[migrate]~ ERROR E0491 //[nll]~^ ERROR lifetime may not live long enough } fn call4<'a, 'b>(a: &'a usize, b: &'b usize) { - let z: Option<&'a &'b usize> = None;//[migrate]~ ERROR E0623 + let z: Option<&'a &'b usize> = None;//[migrate]~ ERROR E0491 //[nll]~^ ERROR lifetime may not live long enough } diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr index 7fbc1622c3a..2f1a4cea8e9 100644 --- a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.stderr @@ -2,7 +2,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-implied-bounds-projection-gap-1.rs:16:10 | LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo) - | -- help: consider adding an explicit lifetime bound `T: 'x`... + | -- help: consider adding an explicit lifetime bound...: `T: 'x +` LL | { LL | wf::<&'x T>(); | ^^^^^ diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.stderr index 382d932e81a..a5a0ff52fac 100644 --- a/src/test/ui/regions/regions-infer-bound-from-trait.stderr +++ b/src/test/ui/regions/regions-infer-bound-from-trait.stderr @@ -2,7 +2,7 @@ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-infer-bound-from-trait.rs:33:5 | LL | fn bar1<'a,A>(x: Inv<'a>, a: A) { - | - help: consider adding an explicit lifetime bound `A: 'a`... + | - help: consider adding an explicit lifetime bound...: `A: 'a` LL | check_bound(x, a) | ^^^^^^^^^^^ | @@ -16,7 +16,7 @@ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-infer-bound-from-trait.rs:37:5 | LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) { - | -- help: consider adding an explicit lifetime bound `A: 'a`... + | -- help: consider adding an explicit lifetime bound...: `A: 'a +` LL | check_bound(x, a) | ^^^^^^^^^^^ | diff --git a/src/test/ui/regions/regions-mock-codegen.rs b/src/test/ui/regions/regions-mock-codegen.rs index f50b1c8b17f..fe3a864fe4b 100644 --- a/src/test/ui/regions/regions-mock-codegen.rs +++ b/src/test/ui/regions/regions-mock-codegen.rs @@ -24,29 +24,29 @@ struct Ccx { x: isize } -fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { +fn alloc(_bcx: &arena) -> &Bcx<'_> { unsafe { let layout = Layout::new::(); - let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let (ptr, _) = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); &*(ptr.as_ptr() as *const _) } } -fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> { +fn h<'a>(bcx: &'a Bcx<'a>) -> &'a Bcx<'a> { return alloc(bcx.fcx.arena); } -fn g(fcx : &Fcx) { - let bcx = Bcx { fcx: fcx }; +fn g(fcx: &Fcx) { + let bcx = Bcx { fcx }; let bcx2 = h(&bcx); unsafe { Global.dealloc(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::()); } } -fn f(ccx : &Ccx) { +fn f(ccx: &Ccx) { let a = arena(()); - let fcx = Fcx { arena: &a, ccx: ccx }; + let fcx = Fcx { arena: &a, ccx }; return g(&fcx); } diff --git a/src/test/ui/regions/regions-trait-object-1.rs b/src/test/ui/regions/regions-trait-object-1.rs index 679bf4dd811..e2520d97890 100644 --- a/src/test/ui/regions/regions-trait-object-1.rs +++ b/src/test/ui/regions/regions-trait-object-1.rs @@ -1,7 +1,7 @@ // run-pass // This is a regression test for something that only came up while -// attempting to bootstrap libsyntax; it is adapted from -// `syntax::ext::tt::generic_extension`. +// attempting to bootstrap librustc_ast; it is adapted from +// `rustc_ast::ext::tt::generic_extension`. pub struct E<'a> { diff --git a/src/test/ui/repr/repr-align-assign.stderr b/src/test/ui/repr/repr-align-assign.stderr index 192312d165b..b878ae0d173 100644 --- a/src/test/ui/repr/repr-align-assign.stderr +++ b/src/test/ui/repr/repr-align-assign.stderr @@ -24,3 +24,4 @@ LL | #[repr(align="8")] error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0693`. diff --git a/src/test/ui/reserved/reserved-attr-on-macro.stderr b/src/test/ui/reserved/reserved-attr-on-macro.stderr index 2870cb57e9c..c387bba0a13 100644 --- a/src/test/ui/reserved/reserved-attr-on-macro.stderr +++ b/src/test/ui/reserved/reserved-attr-on-macro.stderr @@ -4,7 +4,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[rustc_attribute_should_be_reserved] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: cannot determine resolution for the macro `foo` diff --git a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs new file mode 100644 index 00000000000..4397baea4a9 --- /dev/null +++ b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs @@ -0,0 +1,6 @@ +fn main() {} + +trait Foo { + fn fn_with_type_named_same_as_local_in_param(b: b); + //~^ ERROR cannot find type `b` in this scope +} diff --git a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr new file mode 100644 index 00000000000..109409d2731 --- /dev/null +++ b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `b` in this scope + --> $DIR/issue-69401-trait-fn-no-body-ty-local.rs:4:53 + | +LL | fn fn_with_type_named_same_as_local_in_param(b: b); + | ^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/resolve/name-clash-nullary.stderr b/src/test/ui/resolve/name-clash-nullary.stderr index aeeb0c45191..2de0b6a4969 100644 --- a/src/test/ui/resolve/name-clash-nullary.stderr +++ b/src/test/ui/resolve/name-clash-nullary.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/name-clash-nullary.rs:2:7 | LL | let None: isize = 42; - | ^^^^ expected `isize`, found enum `std::option::Option` + | ^^^^ ----- expected due to this + | | + | expected `isize`, found enum `std::option::Option` | = note: expected type `isize` found enum `std::option::Option<_>` diff --git a/src/test/ui/resolve/raw-ident-in-path.rs b/src/test/ui/resolve/raw-ident-in-path.rs new file mode 100644 index 00000000000..1bcbef59437 --- /dev/null +++ b/src/test/ui/resolve/raw-ident-in-path.rs @@ -0,0 +1,5 @@ +// Regression test for issue #63882. + +type A = crate::r#break; //~ ERROR cannot find type `r#break` in module `crate` + +fn main() {} diff --git a/src/test/ui/resolve/raw-ident-in-path.stderr b/src/test/ui/resolve/raw-ident-in-path.stderr new file mode 100644 index 00000000000..f2efcbc8e85 --- /dev/null +++ b/src/test/ui/resolve/raw-ident-in-path.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `r#break` in module `crate` + --> $DIR/raw-ident-in-path.rs:3:17 + | +LL | type A = crate::r#break; + | ^^^^^^^ not found in `crate` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/resolve/resolve-inconsistent-binding-mode.rs b/src/test/ui/resolve/resolve-inconsistent-binding-mode.rs index e9c4e47f887..43e9378b7d0 100644 --- a/src/test/ui/resolve/resolve-inconsistent-binding-mode.rs +++ b/src/test/ui/resolve/resolve-inconsistent-binding-mode.rs @@ -1,39 +1,40 @@ enum Opts { - A(isize), B(isize), C(isize) + A(isize), + B(isize), + C(isize), } fn matcher1(x: Opts) { match x { - Opts::A(ref i) | Opts::B(i) => {} - //~^ ERROR variable `i` is bound in inconsistent ways within the same match arm - //~^^ ERROR mismatched types - Opts::C(_) => {} + Opts::A(ref i) | Opts::B(i) => {} + //~^ ERROR variable `i` is bound inconsistently + //~^^ ERROR mismatched types + Opts::C(_) => {} } } fn matcher2(x: Opts) { match x { - Opts::A(ref i) | Opts::B(i) => {} - //~^ ERROR variable `i` is bound in inconsistent ways within the same match arm - //~^^ ERROR mismatched types - Opts::C(_) => {} + Opts::A(ref i) | Opts::B(i) => {} + //~^ ERROR variable `i` is bound inconsistently + //~^^ ERROR mismatched types + Opts::C(_) => {} } } fn matcher4(x: Opts) { match x { - Opts::A(ref mut i) | Opts::B(ref i) => {} - //~^ ERROR variable `i` is bound in inconsistent ways within the same match arm - //~^^ ERROR mismatched types - Opts::C(_) => {} + Opts::A(ref mut i) | Opts::B(ref i) => {} + //~^ ERROR variable `i` is bound inconsistently + //~^^ ERROR mismatched types + Opts::C(_) => {} } } - fn matcher5(x: Opts) { match x { - Opts::A(ref i) | Opts::B(ref i) => {} - Opts::C(_) => {} + Opts::A(ref i) | Opts::B(ref i) => {} + Opts::C(_) => {} } } diff --git a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr index 61d1001ce91..c14dfa3601a 100644 --- a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr @@ -1,51 +1,62 @@ -error[E0409]: variable `i` is bound in inconsistent ways within the same match arm - --> $DIR/resolve-inconsistent-binding-mode.rs:7:32 +error[E0409]: variable `i` is bound inconsistently across alternatives separated by `|` + --> $DIR/resolve-inconsistent-binding-mode.rs:9:34 | -LL | Opts::A(ref i) | Opts::B(i) => {} - | - ^ bound in different ways - | | - | first binding +LL | Opts::A(ref i) | Opts::B(i) => {} + | - ^ bound in different ways + | | + | first binding -error[E0409]: variable `i` is bound in inconsistent ways within the same match arm - --> $DIR/resolve-inconsistent-binding-mode.rs:16:32 +error[E0409]: variable `i` is bound inconsistently across alternatives separated by `|` + --> $DIR/resolve-inconsistent-binding-mode.rs:18:34 | -LL | Opts::A(ref i) | Opts::B(i) => {} - | - ^ bound in different ways - | | - | first binding +LL | Opts::A(ref i) | Opts::B(i) => {} + | - ^ bound in different ways + | | + | first binding -error[E0409]: variable `i` is bound in inconsistent ways within the same match arm - --> $DIR/resolve-inconsistent-binding-mode.rs:25:40 +error[E0409]: variable `i` is bound inconsistently across alternatives separated by `|` + --> $DIR/resolve-inconsistent-binding-mode.rs:27:42 | -LL | Opts::A(ref mut i) | Opts::B(ref i) => {} - | - first binding ^ bound in different ways +LL | Opts::A(ref mut i) | Opts::B(ref i) => {} + | - first binding ^ bound in different ways error[E0308]: mismatched types - --> $DIR/resolve-inconsistent-binding-mode.rs:7:32 + --> $DIR/resolve-inconsistent-binding-mode.rs:9:34 | LL | match x { | - this expression has type `Opts` -LL | Opts::A(ref i) | Opts::B(i) => {} - | ^ expected `&isize`, found `isize` +LL | Opts::A(ref i) | Opts::B(i) => {} + | ----- ^ expected `&isize`, found `isize` + | | + | first introduced with type `&isize` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types - --> $DIR/resolve-inconsistent-binding-mode.rs:16:32 + --> $DIR/resolve-inconsistent-binding-mode.rs:18:34 | LL | match x { | - this expression has type `Opts` -LL | Opts::A(ref i) | Opts::B(i) => {} - | ^ expected `&isize`, found `isize` +LL | Opts::A(ref i) | Opts::B(i) => {} + | ----- ^ expected `&isize`, found `isize` + | | + | first introduced with type `&isize` here + | + = note: in the same arm, a binding must have the same type in all alternatives error[E0308]: mismatched types - --> $DIR/resolve-inconsistent-binding-mode.rs:25:36 + --> $DIR/resolve-inconsistent-binding-mode.rs:27:38 | LL | match x { | - this expression has type `Opts` -LL | Opts::A(ref mut i) | Opts::B(ref i) => {} - | ^^^^^ types differ in mutability +LL | Opts::A(ref mut i) | Opts::B(ref i) => {} + | --------- ^^^^^ types differ in mutability + | | + | first introduced with type `&mut isize` here | = note: expected type `&mut isize` found type `&isize` + = note: in the same arm, a binding must have the same type in all alternatives error: aborting due to 6 previous errors diff --git a/src/test/ui/resolve/resolve-inconsistent-names.rs b/src/test/ui/resolve/resolve-inconsistent-names.rs index 2fb803c4b2a..b9202f556d1 100644 --- a/src/test/ui/resolve/resolve-inconsistent-names.rs +++ b/src/test/ui/resolve/resolve-inconsistent-names.rs @@ -19,7 +19,7 @@ fn main() { (A, B) | (ref B, c) | (c, A) => () //~^ ERROR variable `A` is not bound in all patterns //~| ERROR variable `B` is not bound in all patterns - //~| ERROR variable `B` is bound in inconsistent ways + //~| ERROR variable `B` is bound inconsistently //~| ERROR mismatched types //~| ERROR variable `c` is not bound in all patterns //~| HELP consider making the path in the pattern qualified: `?::A` diff --git a/src/test/ui/resolve/resolve-inconsistent-names.stderr b/src/test/ui/resolve/resolve-inconsistent-names.stderr index 5c87f7c684f..70e9c2e5bf5 100644 --- a/src/test/ui/resolve/resolve-inconsistent-names.stderr +++ b/src/test/ui/resolve/resolve-inconsistent-names.stderr @@ -47,7 +47,7 @@ LL | (A, B) | (ref B, c) | (c, A) => () | | variable not in all patterns | pattern doesn't bind `c` -error[E0409]: variable `B` is bound in inconsistent ways within the same match arm +error[E0409]: variable `B` is bound inconsistently across alternatives separated by `|` --> $DIR/resolve-inconsistent-names.rs:19:23 | LL | (A, B) | (ref B, c) | (c, A) => () @@ -89,7 +89,11 @@ error[E0308]: mismatched types LL | match x { | - this expression has type `(E, E)` LL | (A, B) | (ref B, c) | (c, A) => () - | ^^^^^ expected enum `E`, found `&E` + | - ^^^^^ expected enum `E`, found `&E` + | | + | first introduced with type `E` here + | + = note: in the same arm, a binding must have the same type in all alternatives error: aborting due to 9 previous errors diff --git a/src/test/ui/resolve/resolve-primitive-fallback.rs b/src/test/ui/resolve/resolve-primitive-fallback.rs index e5a3d689d23..992bcd7977f 100644 --- a/src/test/ui/resolve/resolve-primitive-fallback.rs +++ b/src/test/ui/resolve/resolve-primitive-fallback.rs @@ -2,7 +2,7 @@ fn main() { // Make sure primitive type fallback doesn't work in value namespace std::mem::size_of(u16); //~^ ERROR expected value, found builtin type `u16` - //~| ERROR this function takes 0 parameters but 1 parameter was supplied + //~| ERROR this function takes 0 arguments but 1 argument was supplied // Make sure primitive type fallback doesn't work with global paths let _: ::u8; diff --git a/src/test/ui/resolve/resolve-primitive-fallback.stderr b/src/test/ui/resolve/resolve-primitive-fallback.stderr index 92c2a032983..9d381a8a94e 100644 --- a/src/test/ui/resolve/resolve-primitive-fallback.stderr +++ b/src/test/ui/resolve/resolve-primitive-fallback.stderr @@ -9,12 +9,19 @@ error[E0412]: cannot find type `u8` in the crate root | LL | let _: ::u8; | ^^ not found in the crate root + | +help: possible candidate is found in another module, you can import it into scope + | +LL | use std::primitive::u8; + | -error[E0061]: this function takes 0 parameters but 1 parameter was supplied +error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/resolve-primitive-fallback.rs:3:5 | LL | std::mem::size_of(u16); - | ^^^^^^^^^^^^^^^^^^^^^^ expected 0 parameters + | ^^^^^^^^^^^^^^^^^ --- supplied 1 argument + | | + | expected 0 arguments error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2005-default-binding-mode/const.stderr b/src/test/ui/rfc-2005-default-binding-mode/const.stderr index f25fc300d7f..10d30ec1a1b 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/const.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/const.stderr @@ -1,8 +1,17 @@ error[E0308]: mismatched types --> $DIR/const.rs:14:9 | +LL | const FOO: Foo = Foo{bar: 5}; + | ----------------------------- constant defined here +... +LL | match &f { + | -- this expression has type `&Foo` LL | FOO => {}, - | ^^^ expected `&Foo`, found struct `Foo` + | ^^^ + | | + | expected `&Foo`, found struct `Foo` + | `FOO` is interpreted as a constant, not a new binding + | help: introduce a new binding instead: `other_foo` error: aborting due to previous error diff --git a/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.rs b/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.rs index aa013d4bf35..b4a0d8145c1 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.rs +++ b/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.rs @@ -4,7 +4,7 @@ pub fn main() { let x = &Some((3, 3)); let _: &i32 = match x { Some((x, 3)) | &Some((ref x, 5)) => x, - //~^ ERROR is bound in inconsistent ways + //~^ ERROR is bound inconsistently _ => &5i32, }; } diff --git a/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.stderr b/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.stderr index ff8dce32b2a..e1e1bf7f6d9 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.stderr @@ -1,4 +1,4 @@ -error[E0409]: variable `x` is bound in inconsistent ways within the same match arm +error[E0409]: variable `x` is bound inconsistently across alternatives separated by `|` --> $DIR/issue-44912-or.rs:6:35 | LL | Some((x, 3)) | &Some((ref x, 5)) => x, diff --git a/src/test/ui/rfc-2005-default-binding-mode/lit.stderr b/src/test/ui/rfc-2005-default-binding-mode/lit.stderr index b0d60c7a4c8..6d18a39606c 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/lit.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/lit.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/lit.rs:7:13 | +LL | match &s { + | -- this expression has type `&&str` LL | "abc" => true, | ^^^^^ expected `&str`, found `str` | @@ -10,6 +12,8 @@ LL | "abc" => true, error[E0308]: mismatched types --> $DIR/lit.rs:16:9 | +LL | match &s { + | -- this expression has type `&&[u8]` LL | b"abc" => true, | ^^^^^^ expected `&[u8]`, found array `[u8; 3]` | diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr index 7becb9c5b60..c2fb8fa1eb6 100644 --- a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr +++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr @@ -8,3 +8,4 @@ LL | struct S; error: aborting due to previous error +For more information about this error, try `rustc --explain E0739`. diff --git a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr index b049d8a4ab3..c3cfc5a4d97 100644 --- a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr @@ -2,7 +2,7 @@ error[E0310]: the parameter type `U` may not live long enough --> $DIR/dont-infer-static.rs:8:5 | LL | struct Foo { - | - help: consider adding an explicit lifetime bound `U: 'static`... + | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | bar: Bar | ^^^^^^^^^^^ | diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr index 87014085667..297fcb088d2 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr @@ -2,7 +2,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:18:18 | LL | enum Ref1<'a, T> { - | - help: consider adding an explicit lifetime bound `T: 'a`... + | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | Ref1Variant1(RequireOutlives<'a, T>) | ^^^^^^^^^^^^^^^^^^^^^^ | @@ -16,7 +16,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:23:25 | LL | enum Ref2<'a, T> { - | - help: consider adding an explicit lifetime bound `T: 'a`... + | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | Ref2Variant1, LL | Ref2Variant2(isize, RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:35:1 | LL | enum RefDouble<'a, 'b, T> { - | ^ - help: consider adding an explicit lifetime bound `T: 'b`... + | ^ - help: consider adding an explicit lifetime bound...: `T: 'b` | _| | | LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>) @@ -52,7 +52,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:36:23 | LL | enum RefDouble<'a, 'b, T> { - | - help: consider adding an explicit lifetime bound `T: 'b`... + | - help: consider adding an explicit lifetime bound...: `T: 'b` LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr index 825c1015c51..f6658891fa6 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr @@ -2,7 +2,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-struct-not-wf.rs:13:5 | LL | impl<'a, T> Trait<'a, T> for usize { - | - help: consider adding an explicit lifetime bound `T: 'a`... + | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = &'a T; | ^^^^^^^^^^^^^^^^^ | @@ -16,7 +16,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-struct-not-wf.rs:21:5 | LL | impl<'a, T> Trait<'a, T> for u32 { - | - help: consider adding an explicit lifetime bound `T: 'a`... + | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = RefOk<'a, T>; | ^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 084f070989b..39874a6c680 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -560,8 +560,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool` | LL | if -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` - | - = note: an implementation of `std::ops::Neg` might be missing for `bool` error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/disallowed-positions.rs:46:8 @@ -748,8 +746,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool` | LL | while -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` - | - = note: an implementation of `std::ops::Neg` might be missing for `bool` error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/disallowed-positions.rs:110:11 @@ -927,8 +923,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool` | LL | -let 0 = 0; | ^^^^^^^^^^ cannot apply unary operator `-` - | - = note: an implementation of `std::ops::Neg` might be missing for `bool` error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/disallowed-positions.rs:183:5 diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs new file mode 100644 index 00000000000..194929fa287 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs @@ -0,0 +1,28 @@ +// ignore-test + +// FIXME: This test should fail since, within a const impl of `Foo`, the bound on `Foo::Bar` should +// require a const impl of `Add` for the associated type. + +#![allow(incomplete_features)] +#![feature(const_trait_impl)] +#![feature(const_fn)] + +struct NonConstAdd(i32); + +impl std::ops::Add for NonConstAdd { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + NonConstAdd(self.0 + rhs.0) + } +} + +trait Foo { + type Bar: std::ops::Add; +} + +impl const Foo for NonConstAdd { + type Bar = NonConstAdd; +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs new file mode 100644 index 00000000000..8e6ef12810c --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs @@ -0,0 +1,30 @@ +#![allow(incomplete_features)] +#![feature(const_trait_impl)] +#![feature(const_fn)] + +pub trait Plus { + fn plus(self, rhs: Self) -> Self; +} + +impl const Plus for i32 { + fn plus(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Plus for u32 { + fn plus(self, rhs: Self) -> Self { + self + rhs + } +} + +pub const fn add_i32(a: i32, b: i32) -> i32 { + a.plus(b) // ok +} + +pub const fn add_u32(a: u32, b: u32) -> u32 { + a.plus(b) + //~^ ERROR calls in constant functions are limited to constant functions +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr new file mode 100644 index 00000000000..0c320d54c76 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr @@ -0,0 +1,9 @@ +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants + --> $DIR/call-const-trait-method-fail.rs:26:5 + | +LL | a.plus(b) + | ^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs new file mode 100644 index 00000000000..6a2112ea554 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-pass.rs @@ -0,0 +1,41 @@ +// run-pass + +#![allow(incomplete_features)] +#![feature(const_trait_impl)] +#![feature(const_fn)] + +struct Int(i32); + +impl const std::ops::Add for Int { + type Output = Int; + + fn add(self, rhs: Self) -> Self { + Int(self.0.plus(rhs.0)) + } +} + +impl const PartialEq for Int { + fn eq(&self, rhs: &Self) -> bool { + self.0 == rhs.0 + } +} + +pub trait Plus { + fn plus(self, rhs: Self) -> Self; +} + +impl const Plus for i32 { + fn plus(self, rhs: Self) -> Self { + self + rhs + } +} + +pub const fn add_i32(a: i32, b: i32) -> i32 { + a.plus(b) +} + +const ADD_INT: Int = Int(1i32) + Int(2i32); + +fn main() { + assert!(ADD_INT == Int(3i32)); +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.rs new file mode 100644 index 00000000000..e148ad9a0ee --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.rs @@ -0,0 +1,33 @@ +#![allow(incomplete_features)] +#![feature(const_trait_impl)] + +pub struct Int(i32); + +impl const std::ops::Add for i32 { + //~^ ERROR conflicting implementations of trait + //~| ERROR only traits defined in the current crate can be implemented for arbitrary types + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl std::ops::Add for Int { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Int(self.0 + rhs.0) + } +} + +impl const std::ops::Add for Int { + //~^ ERROR conflicting implementations of trait + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Int(self.0 + rhs.0) + } +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr new file mode 100644 index 00000000000..b57472d9595 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr @@ -0,0 +1,34 @@ +error[E0119]: conflicting implementations of trait `std::ops::Add` for type `i32`: + --> $DIR/const-and-non-const-impl.rs:6:1 + | +LL | impl const std::ops::Add for i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl std::ops::Add for i32; + +error[E0119]: conflicting implementations of trait `std::ops::Add` for type `Int`: + --> $DIR/const-and-non-const-impl.rs:24:1 + | +LL | impl std::ops::Add for Int { + | -------------------------- first implementation here +... +LL | impl const std::ops::Add for Int { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Int` + +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/const-and-non-const-impl.rs:6:1 + | +LL | impl const std::ops::Add for i32 { + | ^^^^^^^^^^^-------------^^^^^--- + | | | | + | | | `i32` is not defined in the current crate + | | `i32` is not defined in the current crate + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0117, E0119. +For more information about an error, try `rustc --explain E0117`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs new file mode 100644 index 00000000000..3278f35bad2 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs @@ -0,0 +1,16 @@ +#![allow(incomplete_features)] +#![feature(const_trait_impl)] + +struct S; +trait T { + fn foo(); +} + +fn non_const() {} + +impl const T for S { + fn foo() { non_const() } + //~^ ERROR can only call other `const fn` +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr new file mode 100644 index 00000000000..7fe3a9fd852 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr @@ -0,0 +1,12 @@ +error[E0723]: can only call other `const fn` within a `const fn`, but `const non_const` is not stable as `const fn` + --> $DIR/const-check-fns-in-const-impl.rs:12:16 + | +LL | fn foo() { non_const() } + | ^^^^^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr index 061af3c94b4..d1ab99e33e9 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.gated.stderr @@ -1,10 +1,8 @@ -error: const trait impls are not yet implemented - --> $DIR/feature-gate.rs:9:1 +error: fatal error triggered by #[rustc_error] + --> $DIR/feature-gate.rs:14:1 | -LL | impl const T for S {} - | ^^^^^-----^^^^^^^^^^^ - | | - | const because of this +LL | fn main() {} + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs index 49b6c0926c5..d9772431941 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.rs @@ -3,11 +3,12 @@ #![cfg_attr(gated, feature(const_trait_impl))] #![allow(incomplete_features)] +#![feature(rustc_attrs)] struct S; trait T {} impl const T for S {} //[stock]~^ ERROR const trait impls are experimental -//[stock,gated]~^^ ERROR const trait impls are not yet implemented -fn main() {} +#[rustc_error] +fn main() {} //[gated]~ ERROR fatal error triggered by #[rustc_error] diff --git a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr index cfe226ea7a7..724090e49cd 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/feature-gate.stock.stderr @@ -1,5 +1,5 @@ error[E0658]: const trait impls are experimental - --> $DIR/feature-gate.rs:9:6 + --> $DIR/feature-gate.rs:10:6 | LL | impl const T for S {} | ^^^^^ @@ -7,14 +7,6 @@ LL | impl const T for S {} = note: see issue #67792 for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable -error: const trait impls are not yet implemented - --> $DIR/feature-gate.rs:9:1 - | -LL | impl const T for S {} - | ^^^^^-----^^^^^^^^^^^ - | | - | const because of this - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/generic-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/generic-bound.rs new file mode 100644 index 00000000000..7829ffe2a38 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/generic-bound.rs @@ -0,0 +1,32 @@ +// run-pass + +#![allow(incomplete_features)] +#![feature(const_trait_impl)] +#![feature(const_fn)] + +use std::marker::PhantomData; + +struct S(PhantomData); + +impl Copy for S {} +impl Clone for S { + fn clone(&self) -> Self { + S(PhantomData) + } +} + +impl const std::ops::Add for S { + type Output = Self; + + fn add(self, _: Self) -> Self { + S(std::marker::PhantomData) + } +} + +const fn twice(arg: S) -> S { + arg + arg +} + +fn main() { + let _ = twice(S(PhantomData::)); +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs index 7f064c0c53a..04123a532bd 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs @@ -8,10 +8,8 @@ trait T {} impl const S {} //~^ ERROR inherent impls cannot be `const` -//~| ERROR const trait impls are not yet implemented impl const T {} //~^ ERROR inherent impls cannot be `const` -//~| ERROR const trait impls are not yet implemented fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr index bdc95ff2a57..834f6a409f5 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr @@ -1,38 +1,22 @@ error: inherent impls cannot be `const` - --> $DIR/inherent-impl.rs:9:1 + --> $DIR/inherent-impl.rs:9:12 | LL | impl const S {} - | ^^^^^-----^^^^^ + | ----- ^ inherent impl for this type | | | `const` because of this | = note: only trait implementations may be annotated with `const` error: inherent impls cannot be `const` - --> $DIR/inherent-impl.rs:13:1 + --> $DIR/inherent-impl.rs:12:12 | LL | impl const T {} - | ^^^^^-----^^^^^ + | ----- ^ inherent impl for this type | | | `const` because of this | = note: only trait implementations may be annotated with `const` -error: const trait impls are not yet implemented - --> $DIR/inherent-impl.rs:9:1 - | -LL | impl const S {} - | ^^^^^-----^^^^^ - | | - | const because of this - -error: const trait impls are not yet implemented - --> $DIR/inherent-impl.rs:13:1 - | -LL | impl const T {} - | ^^^^^-----^^^^^ - | | - | const because of this - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.rs b/src/test/ui/rfc-2632-const-trait-impl/stability.rs new file mode 100644 index 00000000000..03a6fb51503 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.rs @@ -0,0 +1,43 @@ +#![allow(incomplete_features)] +#![feature(allow_internal_unstable)] +#![feature(const_add)] +#![feature(const_trait_impl)] +#![feature(staged_api)] + +pub struct Int(i32); + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +impl const std::ops::Sub for Int { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + //~^ ERROR trait methods cannot be stable const fn + Int(self.0 - rhs.0) + } +} + +#[rustc_const_unstable(feature = "const_add", issue = "none")] +impl const std::ops::Add for Int { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Int(self.0 + rhs.0) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +pub const fn foo() -> Int { + Int(1i32) + Int(2i32) + //~^ ERROR can only call other `const fn` within a `const fn` +} + +// ok +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "bar", issue = "none")] +pub const fn bar() -> Int { + Int(1i32) + Int(2i32) +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr new file mode 100644 index 00000000000..1ecff62955b --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr @@ -0,0 +1,24 @@ +error[E0723]: trait methods cannot be stable const fn + --> $DIR/stability.rs:14:5 + | +LL | / fn sub(self, rhs: Self) -> Self { +LL | | +LL | | Int(self.0 - rhs.0) +LL | | } + | |_____^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error[E0723]: can only call other `const fn` within a `const fn`, but `const ::add` is not stable as `const fn` + --> $DIR/stability.rs:32:5 + | +LL | Int(1i32) + Int(2i32) + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/rust-2018/macro-use-warned-against.rs b/src/test/ui/rust-2018/macro-use-warned-against.rs index 6cd54aa68ae..65400163ddd 100644 --- a/src/test/ui/rust-2018/macro-use-warned-against.rs +++ b/src/test/ui/rust-2018/macro-use-warned-against.rs @@ -4,7 +4,7 @@ #![warn(macro_use_extern_crate, unused)] -#[macro_use] //~ WARN should be replaced at use sites with a `use` statement +#[macro_use] //~ WARN should be replaced at use sites with a `use` item extern crate macro_use_warned_against; #[macro_use] //~ WARN unused `#[macro_use]` extern crate macro_use_warned_against2; diff --git a/src/test/ui/rust-2018/macro-use-warned-against.stderr b/src/test/ui/rust-2018/macro-use-warned-against.stderr index 611b9d5dac9..ef00b865815 100644 --- a/src/test/ui/rust-2018/macro-use-warned-against.stderr +++ b/src/test/ui/rust-2018/macro-use-warned-against.stderr @@ -1,4 +1,4 @@ -warning: deprecated `#[macro_use]` directive used to import macros should be replaced at use sites with a `use` statement to import the macro instead +warning: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead --> $DIR/macro-use-warned-against.rs:7:1 | LL | #[macro_use] diff --git a/src/test/ui/sanitize/address.rs b/src/test/ui/sanitize/address.rs index d27a30a2dc5..f8650cd86d5 100644 --- a/src/test/ui/sanitize/address.rs +++ b/src/test/ui/sanitize/address.rs @@ -1,16 +1,15 @@ // needs-sanitizer-support // only-x86_64 // -// compile-flags: -Z sanitizer=address -O +// compile-flags: -Z sanitizer=address -O -g // // run-fail // error-pattern: AddressSanitizer: stack-buffer-overflow -// error-pattern: 'xs' <== Memory access at offset +// error-pattern: 'xs' (line 15) <== Memory access at offset #![feature(test)] use std::hint::black_box; -use std::mem; fn main() { let xs = [0, 1, 2, 3]; diff --git a/src/test/ui/sanitize/badfree.rs b/src/test/ui/sanitize/badfree.rs new file mode 100644 index 00000000000..1ca082c8b47 --- /dev/null +++ b/src/test/ui/sanitize/badfree.rs @@ -0,0 +1,19 @@ +// needs-sanitizer-support +// only-x86_64 +// +// compile-flags: -Z sanitizer=address -O +// +// run-fail +// error-pattern: AddressSanitizer: SEGV + +use std::ffi::c_void; + +extern "C" { + fn free(ptr: *mut c_void); +} + +fn main() { + unsafe { + free(1 as *mut c_void); + } +} diff --git a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs new file mode 100644 index 00000000000..d0984bbe65f --- /dev/null +++ b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs @@ -0,0 +1,27 @@ +// Regression test for sanitizer function instrumentation passes not +// being run when compiling with new LLVM pass manager and ThinLTO. +// Note: The issue occurred only on non-zero opt-level. +// +// min-llvm-version 9.0 +// needs-sanitizer-support +// only-x86_64 +// +// no-prefer-dynamic +// revisions: opt0 opt1 +// compile-flags: -Znew-llvm-pass-manager=yes -Zsanitizer=address -Clto=thin +//[opt0]compile-flags: -Copt-level=0 +//[opt1]compile-flags: -Copt-level=1 +// run-fail +// error-pattern: ERROR: AddressSanitizer: stack-use-after-scope + +static mut P: *mut usize = std::ptr::null_mut(); + +fn main() { + unsafe { + { + let mut x = 0; + P = &mut x; + } + std::ptr::write_volatile(P, 123); + } +} diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr index b05940fd273..57374b7e3bb 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.nll.stderr @@ -1,16 +1,8 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:45 - | -LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52 | LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } - | - - ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | - - ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` | | | | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` @@ -19,28 +11,19 @@ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:75 | LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } - | - - ^^^^^^^^^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | - - ^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` | | | | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:58 - | -LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } - | ^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64 | LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } - | -- - ^^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` + | -- - ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` | | | | | let's call the lifetime of this reference `'1` | lifetime `'a` defined here -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr index 1a0904fcbba..17099201d11 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr @@ -2,7 +2,7 @@ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:6:46 | LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } - | - - ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | - - ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` | | | | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` @@ -11,7 +11,7 @@ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:69 | LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } - | - - ^^^^^^^^^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | - - ^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` | | | | | let's call the lifetime of this reference `'1` | let's call the lifetime of this reference `'2` @@ -20,7 +20,7 @@ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:13:58 | LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } - | -- ---- has type `std::pin::Pin<&'1 Foo>` ^^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` + | -- ---- has type `std::pin::Pin<&'1 Foo>` ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` | | | lifetime `'a` defined here diff --git a/src/test/ui/self/elision/lt-ref-self-async.nll.stderr b/src/test/ui/self/elision/lt-ref-self-async.nll.stderr index 8dd823a2204..c10b8824e6d 100644 --- a/src/test/ui/self/elision/lt-ref-self-async.nll.stderr +++ b/src/test/ui/self/elision/lt-ref-self-async.nll.stderr @@ -1,11 +1,3 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:12:42 - | -LL | async fn ref_self(&self, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r - error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:13:9 | @@ -14,15 +6,7 @@ LL | async fn ref_self(&self, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:18:48 - | -LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:19:9 @@ -32,15 +16,7 @@ LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:22:57 - | -LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:23:9 @@ -50,15 +26,7 @@ LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:26:57 - | -LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:27:9 @@ -68,15 +36,7 @@ LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:30:66 - | -LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:31:9 @@ -86,15 +46,7 @@ LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/lt-ref-self-async.rs:34:62 - | -LL | async fn box_pin_Self(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#23r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/lt-ref-self-async.rs:35:9 @@ -104,8 +56,7 @@ LL | async fn box_pin_Self(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error: aborting due to 12 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/self/elision/lt-ref-self.nll.stderr b/src/test/ui/self/elision/lt-ref-self.nll.stderr index a0c56f22218..e2de743b8f6 100644 --- a/src/test/ui/self/elision/lt-ref-self.nll.stderr +++ b/src/test/ui/self/elision/lt-ref-self.nll.stderr @@ -6,7 +6,7 @@ LL | fn ref_self(&self, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/lt-ref-self.rs:17:9 @@ -16,7 +16,7 @@ LL | fn ref_Self(self: &Self, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/lt-ref-self.rs:21:9 @@ -26,7 +26,7 @@ LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/lt-ref-self.rs:25:9 @@ -36,7 +36,7 @@ LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/lt-ref-self.rs:29:9 @@ -46,7 +46,7 @@ LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/lt-ref-self.rs:33:9 @@ -56,7 +56,7 @@ LL | fn box_pin_Self(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: aborting due to 6 previous errors diff --git a/src/test/ui/self/elision/ref-mut-self-async.nll.stderr b/src/test/ui/self/elision/ref-mut-self-async.nll.stderr index 768f532c183..19496a5ef6d 100644 --- a/src/test/ui/self/elision/ref-mut-self-async.nll.stderr +++ b/src/test/ui/self/elision/ref-mut-self-async.nll.stderr @@ -1,11 +1,3 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:12:46 - | -LL | async fn ref_self(&mut self, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:13:9 | @@ -14,15 +6,7 @@ LL | async fn ref_self(&mut self, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:18:52 - | -LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:19:9 @@ -32,15 +16,7 @@ LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:22:61 - | -LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:23:9 @@ -50,15 +26,7 @@ LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:26:61 - | -LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:27:9 @@ -68,15 +36,7 @@ LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:30:70 - | -LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:31:9 @@ -86,15 +46,7 @@ LL | async fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-self-async.rs:34:70 - | -LL | async fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-self-async.rs:35:9 @@ -104,8 +56,7 @@ LL | async fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error: aborting due to 12 previous errors +error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/self/elision/ref-mut-self.nll.stderr b/src/test/ui/self/elision/ref-mut-self.nll.stderr index 4e7d7f521d2..94bfc5f4a81 100644 --- a/src/test/ui/self/elision/ref-mut-self.nll.stderr +++ b/src/test/ui/self/elision/ref-mut-self.nll.stderr @@ -6,7 +6,7 @@ LL | fn ref_self(&mut self, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-self.rs:17:9 @@ -16,7 +16,7 @@ LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-self.rs:21:9 @@ -26,7 +26,7 @@ LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-self.rs:25:9 @@ -36,7 +36,7 @@ LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-self.rs:29:9 @@ -46,7 +46,7 @@ LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-self.rs:33:9 @@ -56,7 +56,7 @@ LL | fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: aborting due to 6 previous errors diff --git a/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr b/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr index 9e26e411d30..94671c7c87a 100644 --- a/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr +++ b/src/test/ui/self/elision/ref-mut-struct-async.nll.stderr @@ -1,11 +1,3 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-struct-async.rs:12:56 - | -LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:13:9 | @@ -14,15 +6,7 @@ LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-struct-async.rs:16:65 - | -LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:17:9 @@ -32,15 +16,7 @@ LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-struct-async.rs:20:65 - | -LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:21:9 @@ -50,15 +26,7 @@ LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-struct-async.rs:24:74 - | -LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:25:9 @@ -68,15 +36,7 @@ LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-mut-struct-async.rs:28:74 - | -LL | async fn box_pin_ref_Struct(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-struct-async.rs:29:9 @@ -86,8 +46,7 @@ LL | async fn box_pin_ref_Struct(self: Box>, f: &u32) -> &u | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error: aborting due to 10 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/self/elision/ref-mut-struct.nll.stderr b/src/test/ui/self/elision/ref-mut-struct.nll.stderr index cec7034cd9f..c9e7479ea5d 100644 --- a/src/test/ui/self/elision/ref-mut-struct.nll.stderr +++ b/src/test/ui/self/elision/ref-mut-struct.nll.stderr @@ -6,7 +6,7 @@ LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-struct.rs:15:9 @@ -16,7 +16,7 @@ LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-struct.rs:19:9 @@ -26,7 +26,7 @@ LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-struct.rs:23:9 @@ -36,7 +36,7 @@ LL | fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-mut-struct.rs:27:9 @@ -46,7 +46,7 @@ LL | fn box_pin_ref_Struct(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: aborting due to 5 previous errors diff --git a/src/test/ui/self/elision/ref-self.nll.stderr b/src/test/ui/self/elision/ref-self.nll.stderr index 20045be0527..d1fd209102e 100644 --- a/src/test/ui/self/elision/ref-self.nll.stderr +++ b/src/test/ui/self/elision/ref-self.nll.stderr @@ -6,7 +6,7 @@ LL | fn ref_self(&self, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-self.rs:27:9 @@ -16,7 +16,7 @@ LL | fn ref_Self(self: &Self, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-self.rs:31:9 @@ -26,7 +26,7 @@ LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-self.rs:35:9 @@ -36,7 +36,7 @@ LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-self.rs:39:9 @@ -46,7 +46,7 @@ LL | fn box_box_ref_Self(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-self.rs:43:9 @@ -56,7 +56,7 @@ LL | fn box_pin_ref_Self(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-self.rs:47:9 @@ -66,7 +66,7 @@ LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: aborting due to 7 previous errors diff --git a/src/test/ui/self/elision/ref-struct-async.nll.stderr b/src/test/ui/self/elision/ref-struct-async.nll.stderr index cbf051205ed..9361b6f3f81 100644 --- a/src/test/ui/self/elision/ref-struct-async.nll.stderr +++ b/src/test/ui/self/elision/ref-struct-async.nll.stderr @@ -1,11 +1,3 @@ -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-struct-async.rs:12:52 - | -LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r - error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:13:9 | @@ -14,15 +6,7 @@ LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-struct-async.rs:16:61 - | -LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:17:9 @@ -32,15 +16,7 @@ LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-struct-async.rs:20:61 - | -LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:21:9 @@ -50,15 +26,7 @@ LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-struct-async.rs:24:70 - | -LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:25:9 @@ -68,15 +36,7 @@ LL | async fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ref-struct-async.rs:28:66 - | -LL | async fn box_pin_Struct(self: Box>, f: &u32) -> &u32 { - | ^^^^ - | - = note: hidden type `impl std::future::Future` captures lifetime '_#15r + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-struct-async.rs:29:9 @@ -86,8 +46,7 @@ LL | async fn box_pin_Struct(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` -error: aborting due to 10 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/self/elision/ref-struct.nll.stderr b/src/test/ui/self/elision/ref-struct.nll.stderr index 31bb9f49a6c..e1cc38b7c95 100644 --- a/src/test/ui/self/elision/ref-struct.nll.stderr +++ b/src/test/ui/self/elision/ref-struct.nll.stderr @@ -6,7 +6,7 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-struct.rs:15:9 @@ -16,7 +16,7 @@ LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-struct.rs:19:9 @@ -26,7 +26,7 @@ LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-struct.rs:23:9 @@ -36,7 +36,7 @@ LL | fn box_box_ref_Struct(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: lifetime may not live long enough --> $DIR/ref-struct.rs:27:9 @@ -46,7 +46,7 @@ LL | fn box_pin_Struct(self: Box>, f: &u32) -> &u32 { | | | let's call the lifetime of this reference `'2` LL | f - | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` error: aborting due to 5 previous errors diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr index 28a7b68a682..37873031da3 100644 --- a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr +++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr @@ -2,16 +2,14 @@ error[E0599]: no method named `foo` found for struct `A` in the current scope --> $DIR/point-at-arbitrary-self-type-trait-method.rs:9:7 | LL | trait B { fn foo(self: Box); } - | --- the method is available for `std::boxed::Box` here + | --- --------- the method might not be found because of this arbitrary self type + | | + | the method is available for `std::boxed::Box` here LL | struct A; | --------- method `foo` not found for this ... LL | A.foo() | ^^^ method not found in `A` - | - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `foo`, perhaps you need to implement it: - candidate #1: `B` error: aborting due to previous error diff --git a/src/test/ui/shadow-bool.rs b/src/test/ui/shadow-bool.rs new file mode 100644 index 00000000000..f290a329eaa --- /dev/null +++ b/src/test/ui/shadow-bool.rs @@ -0,0 +1,18 @@ +// check-pass + +mod bar { + pub trait QueryId { + const SOME_PROPERTY: bool; + } +} + +use bar::QueryId; + +#[allow(non_camel_case_types)] +pub struct bool; + +impl QueryId for bool { + const SOME_PROPERTY: core::primitive::bool = true; +} + +fn main() {} diff --git a/src/test/ui/shadowed/shadowed-use-visibility.stderr b/src/test/ui/shadowed/shadowed-use-visibility.stderr index cd8ec13794c..2244f3a46b2 100644 --- a/src/test/ui/shadowed/shadowed-use-visibility.stderr +++ b/src/test/ui/shadowed/shadowed-use-visibility.stderr @@ -4,11 +4,16 @@ error[E0603]: module import `bar` is private LL | use foo::bar::f as g; | ^^^ this module import is private | -note: the module import `bar` is defined here +note: the module import `bar` is defined here... --> $DIR/shadowed-use-visibility.rs:4:9 | LL | use foo as bar; | ^^^^^^^^^^ +note: ...and refers to the module `foo` which is defined here + --> $DIR/shadowed-use-visibility.rs:1:1 + | +LL | mod foo { + | ^^^^^^^ error[E0603]: module import `f` is private --> $DIR/shadowed-use-visibility.rs:15:10 @@ -16,11 +21,16 @@ error[E0603]: module import `f` is private LL | use bar::f::f; | ^ this module import is private | -note: the module import `f` is defined here +note: the module import `f` is defined here... --> $DIR/shadowed-use-visibility.rs:11:9 | LL | use foo as f; | ^^^^^^^^ +note: ...and refers to the module `foo` which is defined here + --> $DIR/shadowed-use-visibility.rs:1:1 + | +LL | mod foo { + | ^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/slightly-nice-generic-literal-messages.stderr b/src/test/ui/slightly-nice-generic-literal-messages.stderr index 61eabed9504..14f01f0ebdf 100644 --- a/src/test/ui/slightly-nice-generic-literal-messages.stderr +++ b/src/test/ui/slightly-nice-generic-literal-messages.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/slightly-nice-generic-literal-messages.rs:7:9 | +LL | match Foo(1.1, marker::PhantomData) { + | ----------------------------- this expression has type `Foo<{float}, _>` LL | 1 => {} | ^ expected struct `Foo`, found integer | diff --git a/src/test/ui/span/E0057.stderr b/src/test/ui/span/E0057.stderr index 6b5890cac36..31579e28289 100644 --- a/src/test/ui/span/E0057.stderr +++ b/src/test/ui/span/E0057.stderr @@ -1,14 +1,18 @@ -error[E0057]: this function takes 1 parameter but 0 parameters were supplied +error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/E0057.rs:3:13 | LL | let a = f(); - | ^^^ expected 1 parameter + | ^-- supplied 0 arguments + | | + | expected 1 argument -error[E0057]: this function takes 1 parameter but 2 parameters were supplied +error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/E0057.rs:5:13 | LL | let c = f(2, 3); - | ^^^^^^^ expected 1 parameter + | ^ - - supplied 2 arguments + | | + | expected 1 argument error: aborting due to 2 previous errors diff --git a/src/test/ui/span/auxiliary/transitive_dep_three.rs b/src/test/ui/span/auxiliary/transitive_dep_three.rs new file mode 100644 index 00000000000..99b51625ac3 --- /dev/null +++ b/src/test/ui/span/auxiliary/transitive_dep_three.rs @@ -0,0 +1,9 @@ +#[macro_export] +macro_rules! define_parse_error { + () => { + #[macro_export] + macro_rules! parse_error { + () => { parse error } + } + } +} diff --git a/src/test/ui/span/auxiliary/transitive_dep_two.rs b/src/test/ui/span/auxiliary/transitive_dep_two.rs new file mode 100644 index 00000000000..5110c42765b --- /dev/null +++ b/src/test/ui/span/auxiliary/transitive_dep_two.rs @@ -0,0 +1,3 @@ +extern crate transitive_dep_three; + +transitive_dep_three::define_parse_error!(); diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 80a237ac6aa..116f5ddd5b4 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -50,14 +50,16 @@ help: if this is a type, explicitly ignore the parameter name LL | fn bar(_: x, y: usize) {} | ^^^^ -error[E0061]: this function takes 2 parameters but 3 parameters were supplied +error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:7:5 | LL | fn foo(Option, String) {} | --------------------------- defined here ... LL | foo(Some(42), 2, ""); - | ^^^^^^^^^^^^^^^^^^^^ expected 2 parameters + | ^^^ -------- - -- supplied 3 arguments + | | + | expected 2 arguments error[E0308]: mismatched types --> $DIR/issue-34264.rs:8:13 @@ -65,14 +67,16 @@ error[E0308]: mismatched types LL | bar("", ""); | ^^ expected `usize`, found `&str` -error[E0061]: this function takes 2 parameters but 3 parameters were supplied +error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:10:5 | LL | fn bar(x, y: usize) {} | ------------------- defined here ... LL | bar(1, 2, 3); - | ^^^^^^^^^^^^ expected 2 parameters + | ^^^ - - - supplied 3 arguments + | | + | expected 2 arguments error: aborting due to 6 previous errors diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index 8a32561bd01..8caa5bea4ac 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -136,8 +136,6 @@ LL | let _ = &c + &d; | -- ^ -- &&str | | | &&str - | - = note: an implementation of `std::ops::Add` might be missing for `&&str` error[E0369]: cannot add `&str` to `&&str` --> $DIR/issue-39018.rs:35:16 @@ -146,8 +144,6 @@ LL | let _ = &c + d; | -- ^ - &str | | | &&str - | - = note: an implementation of `std::ops::Add` might be missing for `&&str` error[E0369]: cannot add `&&str` to `&str` --> $DIR/issue-39018.rs:36:15 diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr index 90a96e3f174..f6344fba3d3 100644 --- a/src/test/ui/span/missing-unit-argument.stderr +++ b/src/test/ui/span/missing-unit-argument.stderr @@ -1,68 +1,72 @@ -error[E0061]: this function takes 1 parameter but 0 parameters were supplied +error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:11:33 | LL | let _: Result<(), String> = Ok(); - | ^^^^ + | ^^-- supplied 0 arguments | help: expected the unit value `()`; create it with empty parentheses | LL | let _: Result<(), String> = Ok(()); | ^^ -error[E0061]: this function takes 2 parameters but 0 parameters were supplied +error[E0061]: this function takes 2 arguments but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:12:5 | LL | fn foo(():(), ():()) {} | -------------------- defined here ... LL | foo(); - | ^^^^^ expected 2 parameters + | ^^^-- supplied 0 arguments + | | + | expected 2 arguments -error[E0061]: this function takes 2 parameters but 1 parameter was supplied +error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing-unit-argument.rs:13:5 | LL | fn foo(():(), ():()) {} | -------------------- defined here ... LL | foo(()); - | ^^^^^^^ expected 2 parameters + | ^^^ -- supplied 1 argument + | | + | expected 2 arguments -error[E0061]: this function takes 1 parameter but 0 parameters were supplied +error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:14:5 | LL | fn bar(():()) {} | ------------- defined here ... LL | bar(); - | ^^^^^ + | ^^^-- supplied 0 arguments | help: expected the unit value `()`; create it with empty parentheses | LL | bar(()); | ^^ -error[E0061]: this function takes 1 parameter but 0 parameters were supplied +error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:15:7 | LL | fn baz(self, (): ()) { } | -------------------- defined here ... LL | S.baz(); - | ^^^ + | ^^^- supplied 0 arguments | help: expected the unit value `()`; create it with empty parentheses | LL | S.baz(()); | ^^ -error[E0061]: this function takes 1 parameter but 0 parameters were supplied +error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:16:7 | LL | fn generic(self, _: T) { } | ------------------------- defined here ... LL | S.generic::<()>(); - | ^^^^^^^ + | ^^^^^^^------ supplied 0 arguments | help: expected the unit value `()`; create it with empty parentheses | diff --git a/src/test/ui/span/transitive-dep-span.rs b/src/test/ui/span/transitive-dep-span.rs new file mode 100644 index 00000000000..b445d389c56 --- /dev/null +++ b/src/test/ui/span/transitive-dep-span.rs @@ -0,0 +1,13 @@ +// Tests that we properly serialize/deserialize spans from transitive dependencies +// (e.g. imported SourceFiles) +// +// The order of these next lines is important, since we need +// transitive_dep_two.rs to be able to reference transitive_dep_three.rs +// +// aux-build: transitive_dep_three.rs +// aux-build: transitive_dep_two.rs +// compile-flags: -Z macro-backtrace + +extern crate transitive_dep_two; + +transitive_dep_two::parse_error!(); //~ ERROR expected one of diff --git a/src/test/ui/span/transitive-dep-span.stderr b/src/test/ui/span/transitive-dep-span.stderr new file mode 100644 index 00000000000..68d8911a435 --- /dev/null +++ b/src/test/ui/span/transitive-dep-span.stderr @@ -0,0 +1,19 @@ +error: expected one of `!` or `::`, found `error` + --> $DIR/auxiliary/transitive_dep_three.rs:6:27 + | +LL | / macro_rules! parse_error { +LL | | () => { parse error } + | | ^^^^^ expected one of `!` or `::` +LL | | } + | |_________- in this expansion of `transitive_dep_two::parse_error!` + | + ::: $DIR/transitive-dep-span.rs:13:1 + | +LL | transitive_dep_two::parse_error!(); + | ----------------------------------- + | | + | in this macro invocation + | in this macro invocation + +error: aborting due to previous error + diff --git a/src/test/ui/span/type-annotations-needed-expr.stderr b/src/test/ui/span/type-annotations-needed-expr.stderr index 2b92f9b93bf..35d994e194f 100644 --- a/src/test/ui/span/type-annotations-needed-expr.stderr +++ b/src/test/ui/span/type-annotations-needed-expr.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let _ = (vec![1,2,3]).into_iter().sum() as f64; | ^^^ | | - | cannot infer type for type parameter `S` declared on the method `sum` + | cannot infer type for type parameter `S` declared on the associated function `sum` | help: consider specifying the type argument in the method call: `sum::` | = note: type must be known at this point diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr index 19809778a5e..a55d79ee035 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr @@ -2,16 +2,22 @@ error[E0599]: no method named `foo_one` found for struct `MyStruct` in the curre --> $DIR/specialization-trait-not-implemented.rs:22:29 | LL | struct MyStruct; - | ---------------- method `foo_one` not found for this + | ---------------- + | | + | method `foo_one` not found for this + | doesn't satisfy `MyStruct: Foo` ... LL | println!("{}", MyStruct.foo_one()); | ^^^^^^^ method not found in `MyStruct` | = note: the method `foo_one` exists but the following trait bounds were not satisfied: - `MyStruct : Foo` + `MyStruct: Foo` = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `foo_one`, perhaps you need to implement it: - candidate #1: `Foo` +note: `Foo` defines an item `foo_one`, perhaps you need to implement it + --> $DIR/specialization-trait-not-implemented.rs:7:1 + | +LL | trait Foo { + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/specialization/defaultimpl/validation.rs b/src/test/ui/specialization/defaultimpl/validation.rs index cf5d6628054..26b3f1ec414 100644 --- a/src/test/ui/specialization/defaultimpl/validation.rs +++ b/src/test/ui/specialization/defaultimpl/validation.rs @@ -4,7 +4,7 @@ struct S; struct Z; -default impl S {} //~ ERROR inherent impls cannot be default +default impl S {} //~ ERROR inherent impls cannot be `default` default unsafe impl Send for S {} //~ ERROR impls of auto traits cannot be default default impl !Send for Z {} //~ ERROR impls of auto traits cannot be default diff --git a/src/test/ui/specialization/defaultimpl/validation.stderr b/src/test/ui/specialization/defaultimpl/validation.stderr index 14a06c39088..6e19d79e48f 100644 --- a/src/test/ui/specialization/defaultimpl/validation.stderr +++ b/src/test/ui/specialization/defaultimpl/validation.stderr @@ -1,10 +1,12 @@ -error: inherent impls cannot be default - --> $DIR/validation.rs:7:1 +error: inherent impls cannot be `default` + --> $DIR/validation.rs:7:14 | LL | default impl S {} - | ^^^^^^^^^^^^^^^^^ + | ------- ^ inherent impl for this type + | | + | `default` because of this | - = note: only trait implementations may be annotated with default + = note: only trait implementations may be annotated with `default` error: impls of auto traits cannot be default --> $DIR/validation.rs:9:1 diff --git a/src/test/ui/specialization/issue-39618.rs b/src/test/ui/specialization/issue-39618.rs new file mode 100644 index 00000000000..20e81e4359b --- /dev/null +++ b/src/test/ui/specialization/issue-39618.rs @@ -0,0 +1,27 @@ +// Regression test for #39618, shouldn't crash. +// FIXME(JohnTitor): Centril pointed out this looks suspicions, we should revisit here. +// More context: https://github.com/rust-lang/rust/pull/69192#discussion_r379846796 + +// check-pass + +#![feature(specialization)] + +trait Foo { + fn foo(&self); +} + +trait Bar { + fn bar(&self); +} + +impl Bar for T where T: Foo { + fn bar(&self) {} +} + +impl Foo for T where T: Bar { + fn foo(&self) {} +} + +impl Foo for u64 {} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/auxiliary/specialization-trait.rs b/src/test/ui/specialization/min_specialization/auxiliary/specialization-trait.rs new file mode 100644 index 00000000000..6ec0d261d51 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/auxiliary/specialization-trait.rs @@ -0,0 +1,6 @@ +#![feature(rustc_attrs)] + +#[rustc_specialization_trait] +pub trait SpecTrait { + fn method(&self); +} diff --git a/src/test/ui/specialization/min_specialization/dyn-trait-assoc-types.rs b/src/test/ui/specialization/min_specialization/dyn-trait-assoc-types.rs new file mode 100644 index 00000000000..03cab00b0fb --- /dev/null +++ b/src/test/ui/specialization/min_specialization/dyn-trait-assoc-types.rs @@ -0,0 +1,32 @@ +// Test that associated types in trait objects are not considered to be +// constrained. + +#![feature(min_specialization)] + +trait Specializable { + fn f(); +} + +trait B { + type Y; +} + +trait C { + type Y; +} + +impl Specializable for A { + default fn f() {} +} + +impl<'a, T> Specializable for dyn B + 'a { + //~^ ERROR specializing impl repeats parameter `T` + fn f() {} +} + +impl<'a, T> Specializable for dyn C + 'a { + //~^ ERROR specializing impl repeats parameter `T` + fn f() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/dyn-trait-assoc-types.stderr b/src/test/ui/specialization/min_specialization/dyn-trait-assoc-types.stderr new file mode 100644 index 00000000000..6345cee2c37 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/dyn-trait-assoc-types.stderr @@ -0,0 +1,20 @@ +error: specializing impl repeats parameter `T` + --> $DIR/dyn-trait-assoc-types.rs:22:1 + | +LL | / impl<'a, T> Specializable for dyn B + 'a { +LL | | +LL | | fn f() {} +LL | | } + | |_^ + +error: specializing impl repeats parameter `T` + --> $DIR/dyn-trait-assoc-types.rs:27:1 + | +LL | / impl<'a, T> Specializable for dyn C + 'a { +LL | | +LL | | fn f() {} +LL | | } + | |_^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/specialization/min_specialization/impl_specialization_trait.rs b/src/test/ui/specialization/min_specialization/impl_specialization_trait.rs new file mode 100644 index 00000000000..723ed71c3e9 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/impl_specialization_trait.rs @@ -0,0 +1,16 @@ +// Check that specialization traits can't be implemented without a feature. + +// gate-test-min_specialization + +// aux-build:specialization-trait.rs + +extern crate specialization_trait; + +struct A {} + +impl specialization_trait::SpecTrait for A { + //~^ ERROR implementing `rustc_specialization_trait` traits is unstable + fn method(&self) {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/impl_specialization_trait.stderr b/src/test/ui/specialization/min_specialization/impl_specialization_trait.stderr new file mode 100644 index 00000000000..934103d49dc --- /dev/null +++ b/src/test/ui/specialization/min_specialization/impl_specialization_trait.stderr @@ -0,0 +1,10 @@ +error: implementing `rustc_specialization_trait` traits is unstable + --> $DIR/impl_specialization_trait.rs:11:1 + | +LL | impl specialization_trait::SpecTrait for A { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(min_specialization)]` to the crate attributes to enable + +error: aborting due to previous error + diff --git a/src/test/ui/specialization/min_specialization/implcit-well-formed-bounds.rs b/src/test/ui/specialization/min_specialization/implcit-well-formed-bounds.rs new file mode 100644 index 00000000000..98d7f919435 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/implcit-well-formed-bounds.rs @@ -0,0 +1,30 @@ +// Test that specializing on the well-formed predicates of the trait and +// self-type of an impl is allowed. + +// check-pass + +#![feature(min_specialization)] + +struct OrdOnly(T); + +trait SpecTrait { + fn f(); +} + +impl SpecTrait for T { + default fn f() {} +} + +impl SpecTrait<()> for OrdOnly { + fn f() {} +} + +impl SpecTrait> for () { + fn f() {} +} + +impl SpecTrait<(OrdOnly, OrdOnly)> for &[OrdOnly] { + fn f() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.rs b/src/test/ui/specialization/min_specialization/repeated_projection_type.rs new file mode 100644 index 00000000000..f21f39f0669 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.rs @@ -0,0 +1,24 @@ +// Test that projection bounds can't be specialized on. + +#![feature(min_specialization)] + +trait X { + fn f(); +} +trait Id { + type This; +} +impl Id for T { + type This = T; +} + +impl X for T { + default fn f() {} +} + +impl> X for V { + //~^ ERROR cannot specialize on + fn f() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr new file mode 100644 index 00000000000..7cc4357a704 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr @@ -0,0 +1,11 @@ +error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id[0]::This[0]) }, (I,)))` + --> $DIR/repeated_projection_type.rs:19:1 + | +LL | / impl> X for V { +LL | | +LL | | fn f() {} +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/specialization/min_specialization/repeating_lifetimes.rs b/src/test/ui/specialization/min_specialization/repeating_lifetimes.rs new file mode 100644 index 00000000000..49bfacec0ae --- /dev/null +++ b/src/test/ui/specialization/min_specialization/repeating_lifetimes.rs @@ -0,0 +1,19 @@ +// Test that directly specializing on repeated lifetime parameters is not +// allowed. + +#![feature(min_specialization)] + +trait X { + fn f(); +} + +impl X for T { + default fn f() {} +} + +impl<'a> X for (&'a u8, &'a u8) { + //~^ ERROR specializing impl repeats parameter `'a` + fn f() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/repeating_lifetimes.stderr b/src/test/ui/specialization/min_specialization/repeating_lifetimes.stderr new file mode 100644 index 00000000000..ce9309f7012 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/repeating_lifetimes.stderr @@ -0,0 +1,11 @@ +error: specializing impl repeats parameter `'a` + --> $DIR/repeating_lifetimes.rs:14:1 + | +LL | / impl<'a> X for (&'a u8, &'a u8) { +LL | | +LL | | fn f() {} +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/specialization/min_specialization/repeating_param.rs b/src/test/ui/specialization/min_specialization/repeating_param.rs new file mode 100644 index 00000000000..5a1c97fd321 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/repeating_param.rs @@ -0,0 +1,17 @@ +// Test that specializing on two type parameters being equal is not allowed. + +#![feature(min_specialization)] + +trait X { + fn f(); +} + +impl X for T { + default fn f() {} +} +impl X for (T, T) { + //~^ ERROR specializing impl repeats parameter `T` + fn f() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/repeating_param.stderr b/src/test/ui/specialization/min_specialization/repeating_param.stderr new file mode 100644 index 00000000000..8b4be1c4995 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/repeating_param.stderr @@ -0,0 +1,11 @@ +error: specializing impl repeats parameter `T` + --> $DIR/repeating_param.rs:12:1 + | +LL | / impl X for (T, T) { +LL | | +LL | | fn f() {} +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/specialization/min_specialization/spec-iter.rs b/src/test/ui/specialization/min_specialization/spec-iter.rs new file mode 100644 index 00000000000..e17e9dd5f13 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/spec-iter.rs @@ -0,0 +1,20 @@ +// Check that we can specialize on a concrete iterator type. This requires us +// to consider which parameters in the parent impl are constrained. + +// check-pass + +#![feature(min_specialization)] + +trait SpecFromIter { + fn f(&self); +} + +impl<'a, T: 'a, I: Iterator> SpecFromIter for I { + default fn f(&self) {} +} + +impl<'a, T> SpecFromIter for std::slice::Iter<'a, T> { + fn f(&self) {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/spec-reference.rs b/src/test/ui/specialization/min_specialization/spec-reference.rs new file mode 100644 index 00000000000..377889e2cca --- /dev/null +++ b/src/test/ui/specialization/min_specialization/spec-reference.rs @@ -0,0 +1,19 @@ +// Check that lifetime parameters are allowed in specializing impls. + +// check-pass + +#![feature(min_specialization)] + +trait MySpecTrait { + fn f(); +} + +impl MySpecTrait for T { + default fn f() {} +} + +impl<'a, T: ?Sized> MySpecTrait for &'a T { + fn f() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/specialization_marker.rs b/src/test/ui/specialization/min_specialization/specialization_marker.rs new file mode 100644 index 00000000000..93462d02ea5 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialization_marker.rs @@ -0,0 +1,17 @@ +// Test that `rustc_unsafe_specialization_marker` is only allowed on marker traits. + +#![feature(rustc_attrs)] + +#[rustc_unsafe_specialization_marker] +trait SpecMarker { + fn f(); + //~^ ERROR marker traits +} + +#[rustc_unsafe_specialization_marker] +trait SpecMarker2 { + type X; + //~^ ERROR marker traits +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/specialization_marker.stderr b/src/test/ui/specialization/min_specialization/specialization_marker.stderr new file mode 100644 index 00000000000..ffeced19821 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialization_marker.stderr @@ -0,0 +1,15 @@ +error[E0714]: marker traits cannot have associated items + --> $DIR/specialization_marker.rs:7:5 + | +LL | fn f(); + | ^^^^^^^ + +error[E0714]: marker traits cannot have associated items + --> $DIR/specialization_marker.rs:13:5 + | +LL | type X; + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/specialization/min_specialization/specialization_super_trait.rs b/src/test/ui/specialization/min_specialization/specialization_super_trait.rs new file mode 100644 index 00000000000..145f376edf9 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialization_super_trait.rs @@ -0,0 +1,18 @@ +// Test that supertraits can't be assumed in impls of +// `rustc_specialization_trait`, as such impls would +// allow specializing on the supertrait. + +#![feature(min_specialization)] +#![feature(rustc_attrs)] + +#[rustc_specialization_trait] +trait SpecMarker: Default { + fn f(); +} + +impl SpecMarker for T { + //~^ ERROR cannot specialize + fn f() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr b/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr new file mode 100644 index 00000000000..154c839c6da --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr @@ -0,0 +1,11 @@ +error: cannot specialize on trait `std::default::Default` + --> $DIR/specialization_super_trait.rs:13:1 + | +LL | / impl SpecMarker for T { +LL | | +LL | | fn f() {} +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/specialization/min_specialization/specialization_trait.rs b/src/test/ui/specialization/min_specialization/specialization_trait.rs new file mode 100644 index 00000000000..d597278d296 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialization_trait.rs @@ -0,0 +1,26 @@ +// Test that `rustc_specialization_trait` requires always applicable impls. + +#![feature(min_specialization)] +#![feature(rustc_attrs)] + +#[rustc_specialization_trait] +trait SpecMarker { + fn f(); +} + +impl SpecMarker for &'static u8 { + //~^ ERROR cannot specialize + fn f() {} +} + +impl SpecMarker for (T, T) { + //~^ ERROR specializing impl + fn f() {} +} + +impl SpecMarker for [T] { + //~^ ERROR cannot specialize + fn f() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/specialization_trait.stderr b/src/test/ui/specialization/min_specialization/specialization_trait.stderr new file mode 100644 index 00000000000..4357d2318fc --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialization_trait.stderr @@ -0,0 +1,29 @@ +error: cannot specialize on `'static` lifetime + --> $DIR/specialization_trait.rs:11:1 + | +LL | / impl SpecMarker for &'static u8 { +LL | | +LL | | fn f() {} +LL | | } + | |_^ + +error: specializing impl repeats parameter `T` + --> $DIR/specialization_trait.rs:16:1 + | +LL | / impl SpecMarker for (T, T) { +LL | | +LL | | fn f() {} +LL | | } + | |_^ + +error: cannot specialize on trait `std::clone::Clone` + --> $DIR/specialization_trait.rs:21:1 + | +LL | / impl SpecMarker for [T] { +LL | | +LL | | fn f() {} +LL | | } + | |_^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/specialization/min_specialization/specialize_on_marker.rs b/src/test/ui/specialization/min_specialization/specialize_on_marker.rs new file mode 100644 index 00000000000..4219bd13b18 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialize_on_marker.rs @@ -0,0 +1,24 @@ +// Test that specializing on a `rustc_unsafe_specialization_marker` trait is +// allowed. + +// check-pass + +#![feature(min_specialization)] +#![feature(rustc_attrs)] + +#[rustc_unsafe_specialization_marker] +trait SpecMarker {} + +trait X { + fn f(); +} + +impl X for T { + default fn f() {} +} + +impl X for T { + fn f() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/specialize_on_spec_trait.rs b/src/test/ui/specialization/min_specialization/specialize_on_spec_trait.rs new file mode 100644 index 00000000000..abbab5c23db --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialize_on_spec_trait.rs @@ -0,0 +1,27 @@ +// Test that specializing on a `rustc_specialization_trait` trait is allowed. + +// check-pass + +#![feature(min_specialization)] +#![feature(rustc_attrs)] + +#[rustc_specialization_trait] +trait SpecTrait { + fn g(&self); +} + +trait X { + fn f(&self); +} + +impl X for T { + default fn f(&self) {} +} + +impl X for T { + fn f(&self) { + self.g(); + } +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/specialize_on_static.rs b/src/test/ui/specialization/min_specialization/specialize_on_static.rs new file mode 100644 index 00000000000..dd1b05401e6 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialize_on_static.rs @@ -0,0 +1,18 @@ +// Test that directly specializing on `'static` is not allowed. + +#![feature(min_specialization)] + +trait X { + fn f(); +} + +impl X for &'_ T { + default fn f() {} +} + +impl X for &'static u8 { + //~^ ERROR cannot specialize on `'static` lifetime + fn f() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/specialize_on_static.stderr b/src/test/ui/specialization/min_specialization/specialize_on_static.stderr new file mode 100644 index 00000000000..d1809d6dfbb --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialize_on_static.stderr @@ -0,0 +1,11 @@ +error: cannot specialize on `'static` lifetime + --> $DIR/specialize_on_static.rs:13:1 + | +LL | / impl X for &'static u8 { +LL | | +LL | | fn f() {} +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/specialization/min_specialization/specialize_on_trait.rs b/src/test/ui/specialization/min_specialization/specialize_on_trait.rs new file mode 100644 index 00000000000..0588442c320 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialize_on_trait.rs @@ -0,0 +1,20 @@ +// Test that specializing on a trait is not allowed in general. + +#![feature(min_specialization)] + +trait SpecMarker {} + +trait X { + fn f(); +} + +impl X for T { + default fn f() {} +} + +impl X for T { + //~^ ERROR cannot specialize on trait `SpecMarker` + fn f() {} +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/specialize_on_trait.stderr b/src/test/ui/specialization/min_specialization/specialize_on_trait.stderr new file mode 100644 index 00000000000..35445fd09b9 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/specialize_on_trait.stderr @@ -0,0 +1,11 @@ +error: cannot specialize on trait `SpecMarker` + --> $DIR/specialize_on_trait.rs:15:1 + | +LL | / impl X for T { +LL | | +LL | | fn f() {} +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/static/static-method-privacy.rs b/src/test/ui/static/static-method-privacy.rs index b637037f60e..9ee59b320ed 100644 --- a/src/test/ui/static/static-method-privacy.rs +++ b/src/test/ui/static/static-method-privacy.rs @@ -6,5 +6,5 @@ mod a { } fn main() { - let _ = a::S::new(); //~ ERROR method `new` is private + let _ = a::S::new(); //~ ERROR associated function `new` is private } diff --git a/src/test/ui/static/static-method-privacy.stderr b/src/test/ui/static/static-method-privacy.stderr index 14ca9f58301..78d211438cc 100644 --- a/src/test/ui/static/static-method-privacy.stderr +++ b/src/test/ui/static/static-method-privacy.stderr @@ -1,4 +1,4 @@ -error[E0624]: method `new` is private +error[E0624]: associated function `new` is private --> $DIR/static-method-privacy.rs:9:13 | LL | let _ = a::S::new(); diff --git a/src/test/ui/suggestions/attribute-typos.stderr b/src/test/ui/suggestions/attribute-typos.stderr index 10a119a628c..c7c257ba5fe 100644 --- a/src/test/ui/suggestions/attribute-typos.stderr +++ b/src/test/ui/suggestions/attribute-typos.stderr @@ -4,7 +4,6 @@ error[E0658]: attributes starting with `rustc` are reserved for use by the `rust LL | #[rustc_err] | ^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: cannot find attribute `rustc_err` in this scope diff --git a/src/test/ui/suggestions/const-in-struct-pat.rs b/src/test/ui/suggestions/const-in-struct-pat.rs new file mode 100644 index 00000000000..1cbba935402 --- /dev/null +++ b/src/test/ui/suggestions/const-in-struct-pat.rs @@ -0,0 +1,11 @@ +#[allow(non_camel_case_types)] +struct foo; +struct Thing { + foo: String, +} + +fn example(t: Thing) { + let Thing { foo } = t; //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/suggestions/const-in-struct-pat.stderr b/src/test/ui/suggestions/const-in-struct-pat.stderr new file mode 100644 index 00000000000..0a010dcab4c --- /dev/null +++ b/src/test/ui/suggestions/const-in-struct-pat.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/const-in-struct-pat.rs:8:17 + | +LL | struct foo; + | ----------- unit struct defined here +... +LL | let Thing { foo } = t; + | ^^^ - this expression has type `Thing` + | | + | expected struct `std::string::String`, found struct `foo` + | `foo` is interpreted as a unit struct, not a new binding + | help: bind the struct field to a different name instead: `foo: other_foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/const-no-type.rs b/src/test/ui/suggestions/const-no-type.rs index 99200a965dd..6b79697e983 100644 --- a/src/test/ui/suggestions/const-no-type.rs +++ b/src/test/ui/suggestions/const-no-type.rs @@ -43,4 +43,4 @@ static S = Vec::::new(); static mut SM = "abc"; //~^ ERROR missing type for `static mut` item //~| HELP provide a type for the item -//~| SUGGESTION &'static str +//~| SUGGESTION &str diff --git a/src/test/ui/suggestions/const-no-type.stderr b/src/test/ui/suggestions/const-no-type.stderr index c4f17109dc5..a7b5aa5e5b1 100644 --- a/src/test/ui/suggestions/const-no-type.stderr +++ b/src/test/ui/suggestions/const-no-type.stderr @@ -14,7 +14,7 @@ error: missing type for `static mut` item --> $DIR/const-no-type.rs:43:12 | LL | static mut SM = "abc"; - | ^^ help: provide a type for the item: `SM: &'static str` + | ^^ help: provide a type for the item: `SM: &str` error: missing type for `const` item --> $DIR/const-no-type.rs:14:7 diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr index abdb754acc5..559a2d29551 100644 --- a/src/test/ui/suggestions/match-ergonomics.stderr +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/match-ergonomics.rs:4:10 | +LL | match &x[..] { + | ------ this expression has type `&[i32]` LL | [&v] => {}, | ^^ | | @@ -25,6 +27,8 @@ LL | [v] => {}, error[E0308]: mismatched types --> $DIR/match-ergonomics.rs:29:9 | +LL | match y { + | - this expression has type `i32` LL | &v => {}, | ^^ | | @@ -38,7 +42,7 @@ error[E0308]: mismatched types --> $DIR/match-ergonomics.rs:40:13 | LL | if let [&v] = &x[..] {} - | ^^ + | ^^ ------ this expression has type `&[i32]` | | | expected `i32`, found reference | help: you can probably remove the explicit borrow: `v` diff --git a/src/test/ui/suggestions/missing-trait-bounds-for-method-call.rs b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.rs new file mode 100644 index 00000000000..fefdf149f55 --- /dev/null +++ b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.rs @@ -0,0 +1,31 @@ +#[derive(Default, PartialEq)] +struct Foo { + bar: Box<[T]>, +} + +trait Bar { + fn foo(&self) {} +} + +impl Bar for Foo {} + +impl Foo { + fn bar(&self) { + self.foo(); + //~^ ERROR no method named `foo` found for reference `&Foo` in the current scope + } +} + +struct Fin where T: Bar { + bar: Box<[T]>, +} + +impl Bar for Fin {} + +impl Fin { + fn bar(&self) { + self.foo(); + //~^ ERROR no method named `foo` found for reference `&Fin` in the current scope + } +} +fn main() {} diff --git a/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr new file mode 100644 index 00000000000..c6d94826c0c --- /dev/null +++ b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr @@ -0,0 +1,39 @@ +error[E0599]: no method named `foo` found for reference `&Foo` in the current scope + --> $DIR/missing-trait-bounds-for-method-call.rs:14:14 + | +LL | struct Foo { + | ------------- doesn't satisfy `Foo: Bar` +... +LL | self.foo(); + | ^^^ method not found in `&Foo` + | + = note: the method `foo` exists but the following trait bounds were not satisfied: + `T: Bar` + which is required by `Foo: Bar` + `T: std::default::Default` + which is required by `Foo: Bar` +help: consider restricting the type parameters to satisfy the trait bounds + | +LL | struct Foo where T: Bar, T: std::default::Default { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `foo` found for reference `&Fin` in the current scope + --> $DIR/missing-trait-bounds-for-method-call.rs:27:14 + | +LL | struct Fin where T: Bar { + | -------------------------- doesn't satisfy `Fin: Bar` +... +LL | self.foo(); + | ^^^ method not found in `&Fin` + | + = note: the method `foo` exists but the following trait bounds were not satisfied: + `T: std::default::Default` + which is required by `Fin: Bar` +help: consider restricting the type parameter to satisfy the trait bound + | +LL | struct Fin where T: Bar, T: std::default::Default { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs index f8b86377187..49a37498fd9 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs @@ -1,3 +1,7 @@ +// FIXME: missing sysroot spans (#53081) +// ignore-i586-unknown-linux-gnu +// ignore-i586-unknown-linux-musl +// ignore-i686-unknown-linux-musl use std::env::args; use std::fs::File; use std::io::{stdout, Write, BufWriter}; diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index 8dc041ace36..e4234cfcd51 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:17:29 + --> $DIR/mut-borrow-needed-by-trait.rs:21:29 | LL | let fp = BufWriter::new(fp); | ^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` @@ -8,7 +8,7 @@ LL | let fp = BufWriter::new(fp); = note: required by `std::io::BufWriter::::new` error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:17:14 + --> $DIR/mut-borrow-needed-by-trait.rs:21:14 | LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` @@ -17,7 +17,7 @@ LL | let fp = BufWriter::new(fp); = note: required by `std::io::BufWriter` error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:17:14 + --> $DIR/mut-borrow-needed-by-trait.rs:21:14 | LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` @@ -26,13 +26,19 @@ LL | let fp = BufWriter::new(fp); = note: required by `std::io::BufWriter` error[E0599]: no method named `write_fmt` found for struct `std::io::BufWriter<&dyn std::io::Write>` in the current scope - --> $DIR/mut-borrow-needed-by-trait.rs:22:5 + --> $DIR/mut-borrow-needed-by-trait.rs:26:5 | LL | writeln!(fp, "hello world").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<&dyn std::io::Write>` + | + ::: $SRC_DIR/libstd/io/buffered.rs:LL:COL + | +LL | pub struct BufWriter { + | ------------------------------ doesn't satisfy `_: std::io::Write` | = note: the method `write_fmt` exists but the following trait bounds were not satisfied: - `std::io::BufWriter<&dyn std::io::Write> : std::io::Write` + `&dyn std::io::Write: std::io::Write` + which is required by `std::io::BufWriter<&dyn std::io::Write>: std::io::Write` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/struct-initializer-comma.rs b/src/test/ui/suggestions/struct-initializer-comma.rs new file mode 100644 index 00000000000..613b976848f --- /dev/null +++ b/src/test/ui/suggestions/struct-initializer-comma.rs @@ -0,0 +1,13 @@ +struct Foo { + first: bool, + second: u8, +} + +fn main() { + let a = Foo { + //~^ ERROR missing field + first: true + second: 25 + //~^ ERROR expected one of + }; +} diff --git a/src/test/ui/suggestions/struct-initializer-comma.stderr b/src/test/ui/suggestions/struct-initializer-comma.stderr new file mode 100644 index 00000000000..731e8e10ab3 --- /dev/null +++ b/src/test/ui/suggestions/struct-initializer-comma.stderr @@ -0,0 +1,23 @@ +error: expected one of `,`, `.`, `?`, `}`, or an operator, found `second` + --> $DIR/struct-initializer-comma.rs:10:9 + | +LL | let a = Foo { + | --- while parsing this struct +LL | +LL | first: true + | - + | | + | expected one of `,`, `.`, `?`, `}`, or an operator + | help: try adding a comma: `,` +LL | second: 25 + | ^^^^^^ unexpected token + +error[E0063]: missing field `second` in initializer of `Foo` + --> $DIR/struct-initializer-comma.rs:7:13 + | +LL | let a = Foo { + | ^^^ missing `second` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0063`. diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.fixed b/src/test/ui/suggestions/suggest-impl-trait-lifetime.fixed index 8592af1262e..589ee1a474a 100644 --- a/src/test/ui/suggestions/suggest-impl-trait-lifetime.fixed +++ b/src/test/ui/suggestions/suggest-impl-trait-lifetime.fixed @@ -3,7 +3,7 @@ use std::fmt::Debug; fn foo(d: impl Debug + 'static) { -//~^ HELP consider adding an explicit lifetime bound `'static` to `impl Debug` +//~^ HELP consider adding an explicit lifetime bound... bar(d); //~^ ERROR the parameter type `impl Debug` may not live long enough //~| NOTE ...so that the type `impl Debug` will meet its required lifetime bounds diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.rs b/src/test/ui/suggestions/suggest-impl-trait-lifetime.rs index c67d78ea4c7..9a87129fbf2 100644 --- a/src/test/ui/suggestions/suggest-impl-trait-lifetime.rs +++ b/src/test/ui/suggestions/suggest-impl-trait-lifetime.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; fn foo(d: impl Debug) { -//~^ HELP consider adding an explicit lifetime bound `'static` to `impl Debug` +//~^ HELP consider adding an explicit lifetime bound... bar(d); //~^ ERROR the parameter type `impl Debug` may not live long enough //~| NOTE ...so that the type `impl Debug` will meet its required lifetime bounds diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr b/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr index cba231d0e86..b6e6c0bbf32 100644 --- a/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr +++ b/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr @@ -1,6 +1,9 @@ error[E0310]: the parameter type `impl Debug` may not live long enough --> $DIR/suggest-impl-trait-lifetime.rs:7:5 | +LL | fn foo(d: impl Debug) { + | ---------- help: consider adding an explicit lifetime bound...: `impl Debug + 'static` +LL | LL | bar(d); | ^^^ | @@ -9,10 +12,6 @@ note: ...so that the type `impl Debug` will meet its required lifetime bounds | LL | bar(d); | ^^^ -help: consider adding an explicit lifetime bound `'static` to `impl Debug`... - | -LL | fn foo(d: impl Debug + 'static) { - | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/suggestions/suggest-methods.stderr b/src/test/ui/suggestions/suggest-methods.stderr index a715c565946..c343071ac3e 100644 --- a/src/test/ui/suggestions/suggest-methods.stderr +++ b/src/test/ui/suggestions/suggest-methods.stderr @@ -5,19 +5,19 @@ LL | struct Foo; | ----------- method `bat` not found for this ... LL | f.bat(1.0); - | ^^^ help: there is a method with a similar name: `bar` + | ^^^ help: there is an associated function with a similar name: `bar` error[E0599]: no method named `is_emtpy` found for struct `std::string::String` in the current scope --> $DIR/suggest-methods.rs:21:15 | LL | let _ = s.is_emtpy(); - | ^^^^^^^^ help: there is a method with a similar name: `is_empty` + | ^^^^^^^^ help: there is an associated function with a similar name: `is_empty` error[E0599]: no method named `count_eos` found for type `u32` in the current scope --> $DIR/suggest-methods.rs:25:19 | LL | let _ = 63u32.count_eos(); - | ^^^^^^^^^ help: there is a method with a similar name: `count_zeros` + | ^^^^^^^^^ help: there is an associated function with a similar name: `count_zeros` error[E0599]: no method named `count_o` found for type `u32` in the current scope --> $DIR/suggest-methods.rs:28:19 diff --git a/src/test/ui/suggestions/suggest-move-types.rs b/src/test/ui/suggestions/suggest-move-types.rs index 890950ea08c..6505a97de6e 100644 --- a/src/test/ui/suggestions/suggest-move-types.rs +++ b/src/test/ui/suggestions/suggest-move-types.rs @@ -33,7 +33,7 @@ struct A> { //~ ERROR associated type bindings must be declar struct Al<'a, T, M: OneWithLifetime> { //~^ ERROR associated type bindings must be declared after generic parameters -//~^^ ERROR lifetime arguments must be declared prior to type arguments +//~^^ ERROR type provided when a lifetime was expected m: M, t: &'a T, } @@ -47,7 +47,7 @@ struct B> { //~ ERROR associated ty struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { //~^ ERROR associated type bindings must be declared after generic parameters -//~^^ ERROR lifetime arguments must be declared prior to type arguments +//~^^ ERROR type provided when a lifetime was expected m: M, t: &'a T, u: &'b U, @@ -63,7 +63,7 @@ struct C> { //~ ERROR associated ty struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { //~^ ERROR associated type bindings must be declared after generic parameters -//~^^ ERROR lifetime arguments must be declared prior to type arguments +//~^^ ERROR lifetime provided when a type was expected m: M, t: &'a T, u: &'b U, @@ -79,7 +79,7 @@ struct D> { //~ ERROR associated ty struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { //~^ ERROR associated type bindings must be declared after generic parameters -//~^^ ERROR lifetime arguments must be declared prior to type arguments +//~^^ ERROR lifetime provided when a type was expected m: M, t: &'a T, u: &'b U, diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr index 552fb78cd3f..ac91813f928 100644 --- a/src/test/ui/suggestions/suggest-move-types.stderr +++ b/src/test/ui/suggestions/suggest-move-types.stderr @@ -74,29 +74,38 @@ LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime $DIR/suggest-move-types.rs:34:46 +error[E0747]: type provided when a lifetime was expected + --> $DIR/suggest-move-types.rs:34:43 | LL | struct Al<'a, T, M: OneWithLifetime> { - | ^^ + | ^ + | + = note: lifetime arguments must be provided before type arguments -error: lifetime arguments must be declared prior to type arguments - --> $DIR/suggest-move-types.rs:48:80 +error[E0747]: type provided when a lifetime was expected + --> $DIR/suggest-move-types.rs:48:71 | LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { - | ^^ ^^ ^^ + | ^ + | + = note: lifetime arguments must be provided before type arguments -error: lifetime arguments must be declared prior to type arguments +error[E0747]: lifetime provided when a type was expected --> $DIR/suggest-move-types.rs:64:56 | LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { - | ^^ ^^ ^^ + | ^^ + | + = note: type arguments must be provided before lifetime arguments -error: lifetime arguments must be declared prior to type arguments +error[E0747]: lifetime provided when a type was expected --> $DIR/suggest-move-types.rs:80:56 | LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { - | ^^ ^^ ^^ + | ^^ + | + = note: type arguments must be provided before lifetime arguments error: aborting due to 12 previous errors +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/suppressed-error.stderr b/src/test/ui/suppressed-error.stderr index 846cd2adcd8..c2874ae9a14 100644 --- a/src/test/ui/suppressed-error.stderr +++ b/src/test/ui/suppressed-error.stderr @@ -2,7 +2,9 @@ error[E0308]: mismatched types --> $DIR/suppressed-error.rs:2:9 | LL | let (x, y) = (); - | ^^^^^^ expected `()`, found tuple + | ^^^^^^ -- this expression has type `()` + | | + | expected `()`, found tuple | = note: expected unit type `()` found tuple `(_, _)` diff --git a/src/test/ui/syntax-trait-polarity-feature-gate.stderr b/src/test/ui/syntax-trait-polarity-feature-gate.stderr index ed76377278b..5d4c1b354f7 100644 --- a/src/test/ui/syntax-trait-polarity-feature-gate.stderr +++ b/src/test/ui/syntax-trait-polarity-feature-gate.stderr @@ -1,8 +1,8 @@ error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now - --> $DIR/syntax-trait-polarity-feature-gate.rs:7:1 + --> $DIR/syntax-trait-polarity-feature-gate.rs:7:6 | LL | impl !Send for TestType {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ | = note: see issue #13231 for more information = help: add `#![feature(optin_builtin_traits)]` to the crate attributes to enable diff --git a/src/test/ui/syntax-trait-polarity.stderr b/src/test/ui/syntax-trait-polarity.stderr index fef3a650888..5777e0ade90 100644 --- a/src/test/ui/syntax-trait-polarity.stderr +++ b/src/test/ui/syntax-trait-polarity.stderr @@ -1,29 +1,35 @@ error: inherent impls cannot be negative - --> $DIR/syntax-trait-polarity.rs:7:1 + --> $DIR/syntax-trait-polarity.rs:7:7 | LL | impl !TestType {} - | ^^^^^^^^^^^^^^^^^ + | -^^^^^^^^ inherent impl for this type + | | + | negative because of this error[E0198]: negative impls cannot be unsafe - --> $DIR/syntax-trait-polarity.rs:12:1 + --> $DIR/syntax-trait-polarity.rs:12:13 | LL | unsafe impl !Send for TestType {} - | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | + | ------ -^^^^ + | | | + | | negative because of this | unsafe because of this error: inherent impls cannot be negative - --> $DIR/syntax-trait-polarity.rs:19:1 + --> $DIR/syntax-trait-polarity.rs:19:10 | LL | impl !TestType2 {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | -^^^^^^^^^^^^ inherent impl for this type + | | + | negative because of this error[E0198]: negative impls cannot be unsafe - --> $DIR/syntax-trait-polarity.rs:22:1 + --> $DIR/syntax-trait-polarity.rs:22:16 | LL | unsafe impl !Send for TestType2 {} - | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | + | ------ -^^^^ + | | | + | | negative because of this | unsafe because of this error[E0192]: negative impls are only allowed for auto traits (e.g., `Send` and `Sync`) diff --git a/src/test/ui/test-panic-while-printing.rs b/src/test/ui/test-panic-while-printing.rs new file mode 100644 index 00000000000..23f45407c1a --- /dev/null +++ b/src/test/ui/test-panic-while-printing.rs @@ -0,0 +1,24 @@ +// compile-flags:--test +// run-pass +// ignore-emscripten no subprocess support + +use std::fmt; +use std::fmt::{Display, Formatter}; + +pub struct A(Vec); + +impl Display for A { + fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result { + self.0[0]; + Ok(()) + } +} + +#[test] +fn main() { + let result = std::panic::catch_unwind(|| { + let a = A(vec![]); + eprintln!("{}", a); + }); + assert!(result.is_err()); +} diff --git a/src/test/ui/tool-attributes/diagnostic_item.stderr b/src/test/ui/tool-attributes/diagnostic_item.stderr index d12834084e7..743e4b658c6 100644 --- a/src/test/ui/tool-attributes/diagnostic_item.stderr +++ b/src/test/ui/tool-attributes/diagnostic_item.stderr @@ -4,7 +4,6 @@ error[E0658]: diagnostic items compiler internal support for linting LL | #[rustc_diagnostic_item = "foomp"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #29642 for more information = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/traits/trait-item-privacy.rs b/src/test/ui/traits/trait-item-privacy.rs index 8507d8ef17e..1ea1d65df62 100644 --- a/src/test/ui/traits/trait-item-privacy.rs +++ b/src/test/ui/traits/trait-item-privacy.rs @@ -69,7 +69,7 @@ fn check_method() { S.c(); // OK // a, b, c are resolved as inherent items, their traits don't need to be in scope let c = &S as &dyn C; - c.a(); //~ ERROR method `a` is private + c.a(); //~ ERROR associated function `a` is private c.b(); // OK c.c(); // OK @@ -81,7 +81,7 @@ fn check_method() { //~^ ERROR no function or associated item named `b` found S::c(&S); // OK // a, b, c are resolved as inherent items, their traits don't need to be in scope - C::a(&S); //~ ERROR method `a` is private + C::a(&S); //~ ERROR associated function `a` is private C::b(&S); // OK C::c(&S); // OK } diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr index 072328ab50c..4b40c6405c4 100644 --- a/src/test/ui/traits/trait-item-privacy.stderr +++ b/src/test/ui/traits/trait-item-privacy.stderr @@ -8,8 +8,11 @@ LL | S.a(); | ^ method not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `a`, perhaps you need to implement it: - candidate #1: `method::A` +note: `method::A` defines an item `a`, perhaps you need to implement it + --> $DIR/trait-item-privacy.rs:6:5 + | +LL | trait A { + | ^^^^^^^ error[E0599]: no method named `b` found for struct `S` in the current scope --> $DIR/trait-item-privacy.rs:68:7 @@ -33,7 +36,7 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f LL | use method::B; | -error[E0624]: method `a` is private +error[E0624]: associated function `a` is private --> $DIR/trait-item-privacy.rs:72:7 | LL | c.a(); @@ -49,8 +52,11 @@ LL | S::a(&S); | ^ function or associated item not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `a`, perhaps you need to implement it: - candidate #1: `method::A` +note: `method::A` defines an item `a`, perhaps you need to implement it + --> $DIR/trait-item-privacy.rs:6:5 + | +LL | trait A { + | ^^^^^^^ error[E0599]: no function or associated item named `b` found for struct `S` in the current scope --> $DIR/trait-item-privacy.rs:80:8 @@ -67,7 +73,7 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f LL | use method::B; | -error[E0624]: method `a` is private +error[E0624]: associated function `a` is private --> $DIR/trait-item-privacy.rs:84:5 | LL | C::a(&S); @@ -83,8 +89,11 @@ LL | S::A; | ^ associated item not found in `S` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `A`, perhaps you need to implement it: - candidate #1: `assoc_const::A` +note: `assoc_const::A` defines an item `A`, perhaps you need to implement it + --> $DIR/trait-item-privacy.rs:24:5 + | +LL | trait A { + | ^^^^^^^ error[E0599]: no associated item named `B` found for struct `S` in the current scope --> $DIR/trait-item-privacy.rs:98:8 diff --git a/src/test/ui/traits/trait-method-private.stderr b/src/test/ui/traits/trait-method-private.stderr index 10552acb348..035c1ea092b 100644 --- a/src/test/ui/traits/trait-method-private.stderr +++ b/src/test/ui/traits/trait-method-private.stderr @@ -1,4 +1,4 @@ -error[E0624]: method `method` is private +error[E0624]: associated function `method` is private --> $DIR/trait-method-private.rs:19:9 | LL | foo.method(); diff --git a/src/test/ui/traits/trait-object-vs-lifetime.rs b/src/test/ui/traits/trait-object-vs-lifetime.rs index e0ff7349483..e885cd2f68a 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.rs +++ b/src/test/ui/traits/trait-object-vs-lifetime.rs @@ -12,6 +12,6 @@ fn main() { //~^ ERROR wrong number of lifetime arguments: expected 1, found 2 //~| ERROR wrong number of type arguments: expected 1, found 0 let _: S; - //~^ ERROR lifetime arguments must be declared prior to type arguments + //~^ ERROR type provided when a lifetime was expected //~| ERROR at least one trait is required for an object type } diff --git a/src/test/ui/traits/trait-object-vs-lifetime.stderr b/src/test/ui/traits/trait-object-vs-lifetime.stderr index be1958770a4..04529fb8cfa 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.stderr +++ b/src/test/ui/traits/trait-object-vs-lifetime.stderr @@ -1,9 +1,3 @@ -error: lifetime arguments must be declared prior to type arguments - --> $DIR/trait-object-vs-lifetime.rs:14:29 - | -LL | let _: S; - | ^^^^^^^ - error[E0224]: at least one trait is required for an object type --> $DIR/trait-object-vs-lifetime.rs:9:23 | @@ -28,6 +22,15 @@ error[E0224]: at least one trait is required for an object type LL | let _: S; | ^^^^^^^^^^^^^ +error[E0747]: type provided when a lifetime was expected + --> $DIR/trait-object-vs-lifetime.rs:14:14 + | +LL | let _: S; + | ^^^^^^^^^^^^^ + | + = note: lifetime arguments must be provided before type arguments + error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0747. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr index 8d7ba36c665..29216f36f5f 100644 --- a/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr +++ b/src/test/ui/traits/trait-resolution-in-overloaded-op.stderr @@ -5,8 +5,6 @@ LL | a * b | - ^ - f64 | | | &T - | - = note: an implementation of `std::ops::Mul` might be missing for `&T` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-safety-inherent-impl.stderr b/src/test/ui/traits/trait-safety-inherent-impl.stderr index c398785d394..0738d2973e2 100644 --- a/src/test/ui/traits/trait-safety-inherent-impl.stderr +++ b/src/test/ui/traits/trait-safety-inherent-impl.stderr @@ -1,14 +1,10 @@ error[E0197]: inherent impls cannot be unsafe - --> $DIR/trait-safety-inherent-impl.rs:5:1 + --> $DIR/trait-safety-inherent-impl.rs:5:13 | -LL | unsafe impl SomeStruct { - | ^----- - | | - | _unsafe because of this +LL | unsafe impl SomeStruct { + | ------ ^^^^^^^^^^ inherent impl for this type | | -LL | | fn foo(self) { } -LL | | } - | |_^ + | unsafe because of this error: aborting due to previous error diff --git a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr index 63182a6bd95..a83ff370151 100644 --- a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr @@ -1,8 +1,10 @@ error[E0568]: auto traits cannot have super traits - --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:7:1 + --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:7:19 | LL | auto trait Magic: Copy {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----- ^^^^ help: remove the super traits + | | + | auto trait cannot have super traits error[E0277]: the trait bound `NoClone: std::marker::Copy` is not satisfied --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:15:23 diff --git a/src/test/ui/transmute/main.stderr b/src/test/ui/transmute/main.stderr index c72876e050f..4e781318329 100644 --- a/src/test/ui/transmute/main.stderr +++ b/src/test/ui/transmute/main.stderr @@ -4,8 +4,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | transmute(x) | ^^^^^^^^^ | - = note: source type: `>::T` (size can vary because of ::T) - = note: target type: `>::T` (size can vary because of ::T) + = note: `::T` does not have a fixed size error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/main.rs:20:17 diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr index acf309ac608..4e153081d9f 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr @@ -15,8 +15,11 @@ LL | 3i32.test(); | ^^^^ method not found in `i32` | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `test`, perhaps you need to implement it: - candidate #1: `Foo` +note: `Foo` defines an item `test`, perhaps you need to implement it + --> $DIR/trivial-bounds-leak.rs:4:1 + | +LL | pub trait Foo { + | ^^^^^^^^^^^^^ error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/trivial-bounds-leak.rs:25:15 diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.rs b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.rs index fa3e1a35fc2..d012687533b 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.rs +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.rs @@ -18,6 +18,6 @@ impl E2 { } fn main() { - ::V(); //~ ERROR this function takes 1 parameter but 0 parameters were supplied + ::V(); //~ ERROR this function takes 1 argument but 0 arguments were supplied let _: u8 = ::V; //~ ERROR mismatched types } diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr index 95c3a08c04a..46e7dd0c517 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr @@ -1,11 +1,13 @@ -error[E0061]: this function takes 1 parameter but 0 parameters were supplied +error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:21:5 | LL | V(u8) | ----- defined here ... LL | ::V(); - | ^^^^^^^^ expected 1 parameter + | ^^^^^^-- supplied 0 arguments + | | + | expected 1 argument error[E0308]: mismatched types --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:22:17 diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-const.rs b/src/test/ui/type-alias-impl-trait/assoc-type-const.rs index 5db677d82e2..2907c21c620 100644 --- a/src/test/ui/type-alias-impl-trait/assoc-type-const.rs +++ b/src/test/ui/type-alias-impl-trait/assoc-type-const.rs @@ -6,7 +6,7 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -trait UnwrapItemsExt { +trait UnwrapItemsExt<'a, const C: usize> { type Iter; fn unwrap_items(self) -> Self::Iter; } @@ -18,18 +18,16 @@ trait MyTrait<'a, const C: usize> { const MY_CONST: usize; } -impl<'a, const C: usize> MyTrait<'a, {C}> for MyStruct<{C}> { +impl<'a, const C: usize> MyTrait<'a, { C }> for MyStruct<{ C }> { type MyItem = u8; const MY_CONST: usize = C; } -impl<'a, I, const C: usize> UnwrapItemsExt<{C}> for I -where -{ - type Iter = impl MyTrait<'a, {C}>; +impl<'a, I, const C: usize> UnwrapItemsExt<'a, { C }> for I { + type Iter = impl MyTrait<'a, { C }>; fn unwrap_items(self) -> Self::Iter { - MyStruct::<{C}> {} + MyStruct::<{ C }> {} } } diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.rs b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.rs new file mode 100644 index 00000000000..3f34b00ec77 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.rs @@ -0,0 +1,26 @@ +// Tests that we don't allow unconstrained lifetime parameters in impls when +// the lifetime is used in an associated opaque type. + +#![feature(type_alias_impl_trait)] + +trait UnwrapItemsExt { + type Iter; + fn unwrap_items(self) -> Self::Iter; +} + +struct MyStruct {} + +trait MyTrait<'a> {} + +impl<'a> MyTrait<'a> for MyStruct {} + +impl<'a, I> UnwrapItemsExt for I { + //~^ ERROR the lifetime parameter `'a` is not constrained + type Iter = impl MyTrait<'a>; + + fn unwrap_items(self) -> Self::Iter { + MyStruct {} + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.stderr b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.stderr new file mode 100644 index 00000000000..e594dc577b1 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime-unconstrained.stderr @@ -0,0 +1,9 @@ +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/assoc-type-lifetime-unconstrained.rs:17:6 + | +LL | impl<'a, I> UnwrapItemsExt for I { + | ^^ unconstrained lifetime parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-lifetime.rs b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime.rs index cff1d24494e..39f785d8cc5 100644 --- a/src/test/ui/type-alias-impl-trait/assoc-type-lifetime.rs +++ b/src/test/ui/type-alias-impl-trait/assoc-type-lifetime.rs @@ -4,7 +4,7 @@ #![feature(type_alias_impl_trait)] -trait UnwrapItemsExt { +trait UnwrapItemsExt<'a> { type Iter; fn unwrap_items(self) -> Self::Iter; } @@ -15,9 +15,7 @@ trait MyTrait<'a> {} impl<'a> MyTrait<'a> for MyStruct {} -impl<'a, I> UnwrapItemsExt for I -where -{ +impl<'a, I> UnwrapItemsExt<'a> for I { type Iter = impl MyTrait<'a>; fn unwrap_items(self) -> Self::Iter { diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs index 59e7de413a2..6cbb3069ecd 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.rs @@ -7,11 +7,11 @@ fn main() {} // test that unused generic parameters are ok type Two = impl Debug; -fn two(t: T, u: U) -> Two { +fn two(t: T, u: U) -> Two { (t, t) } -fn three(t: T, u: U) -> Two { -//~^ concrete type differs from previous +fn three(t: T, u: U) -> Two { + //~^ concrete type differs from previous (u, t) } diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr index 66649413d38..7e81d362661 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use6.stderr @@ -1,7 +1,7 @@ error: concrete type differs from previous defining opaque type use --> $DIR/generic_duplicate_param_use6.rs:14:1 | -LL | / fn three(t: T, u: U) -> Two { +LL | / fn three(t: T, u: U) -> Two { LL | | LL | | (u, t) LL | | } @@ -10,7 +10,7 @@ LL | | } note: previous use here --> $DIR/generic_duplicate_param_use6.rs:10:1 | -LL | / fn two(t: T, u: U) -> Two { +LL | / fn two(t: T, u: U) -> Two { LL | | (t, t) LL | | } | |_^ diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr index 5a7f9d74eba..22e2391f838 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr @@ -25,7 +25,7 @@ LL | type WrongGeneric = impl 'static; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | fn wrong_generic(t: T) -> WrongGeneric { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` | note: ...so that the type `T` will meet its required lifetime bounds --> $DIR/generic_type_does_not_live_long_enough.rs:9:1 diff --git a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.rs b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.rs index a102d16078b..50eeff0b18f 100644 --- a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.rs +++ b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.rs @@ -7,7 +7,7 @@ use std::fmt::Debug; fn main() { type Opaque = impl Debug; fn _unused() -> Opaque { String::new() } - //~^ ERROR: concrete type differs from previous defining opaque type use let null = || -> Opaque { 0 }; + //~^ ERROR: concrete type differs from previous defining opaque type use println!("{:?}", null()); } diff --git a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr index c994eb5986c..1333b4c63d1 100644 --- a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr @@ -1,20 +1,14 @@ error: concrete type differs from previous defining opaque type use - --> $DIR/issue-52843-closure-constrain.rs:9:5 + --> $DIR/issue-52843-closure-constrain.rs:10:16 | -LL | fn _unused() -> Opaque { String::new() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, got `std::string::String` +LL | let null = || -> Opaque { 0 }; + | ^^^^^^^^^^^^^^^^^^ expected `std::string::String`, got `i32` | note: previous use here - --> $DIR/issue-52843-closure-constrain.rs:7:1 + --> $DIR/issue-52843-closure-constrain.rs:9:5 | -LL | / fn main() { -LL | | type Opaque = impl Debug; -LL | | fn _unused() -> Opaque { String::new() } -LL | | -LL | | let null = || -> Opaque { 0 }; -LL | | println!("{:?}", null()); -LL | | } - | |_^ +LL | fn _unused() -> Opaque { String::new() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.rs b/src/test/ui/type-alias-impl-trait/issue-60564.rs index 8686100205f..73acc92172b 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs @@ -8,7 +8,7 @@ trait IterBits { type IterBitsIter = impl std::iter::Iterator; //~^ ERROR could not find defining uses -impl IterBits for T +impl IterBits for T where T: std::ops::Shr + std::ops::BitAnd diff --git a/src/test/ui/type-alias-impl-trait/issue-65918.rs b/src/test/ui/type-alias-impl-trait/issue-65918.rs index 4ba778d53ac..af6d5010920 100644 --- a/src/test/ui/type-alias-impl-trait/issue-65918.rs +++ b/src/test/ui/type-alias-impl-trait/issue-65918.rs @@ -6,7 +6,7 @@ use std::marker::PhantomData; -/* copied Index and TryFrom for convinience (and simplicity) */ +/* copied Index and TryFrom for convenience (and simplicity) */ trait MyIndex { type O; fn my_index(self) -> Self::O; diff --git a/src/test/ui/type-alias-impl-trait/issue-67844-nested-opaque.rs b/src/test/ui/type-alias-impl-trait/issue-67844-nested-opaque.rs index 2f844b4a05f..7da0b049264 100644 --- a/src/test/ui/type-alias-impl-trait/issue-67844-nested-opaque.rs +++ b/src/test/ui/type-alias-impl-trait/issue-67844-nested-opaque.rs @@ -1,6 +1,6 @@ // check-pass // Regression test for issue #67844 -// Ensures that we properly handle nested TAIT occurences +// Ensures that we properly handle nested TAIT occurrences // with generic parameters #![feature(type_alias_impl_trait)] diff --git a/src/test/ui/type-inference/or_else-multiple-type-params.stderr b/src/test/ui/type-inference/or_else-multiple-type-params.stderr index b9258b20f5a..24122e65867 100644 --- a/src/test/ui/type-inference/or_else-multiple-type-params.stderr +++ b/src/test/ui/type-inference/or_else-multiple-type-params.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | .or_else(|err| { | ^^^^^^^ | | - | cannot infer type for type parameter `F` declared on the method `or_else` + | cannot infer type for type parameter `F` declared on the associated function `or_else` | help: consider specifying the type arguments in the method call: `or_else::` error: aborting due to previous error diff --git a/src/test/ui/type-inference/sort_by_key.stderr b/src/test/ui/type-inference/sort_by_key.stderr index e74c0dfa5e2..bb108adcd64 100644 --- a/src/test/ui/type-inference/sort_by_key.stderr +++ b/src/test/ui/type-inference/sort_by_key.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | lst.sort_by_key(|&(v, _)| v.iter().sum()); | ^^^^^^^^^^^ --- help: consider specifying the type argument in the method call: `sum::` | | - | cannot infer type for type parameter `K` declared on the method `sort_by_key` + | cannot infer type for type parameter `K` declared on the associated function `sort_by_key` error: aborting due to previous error diff --git a/src/test/ui/type/ascription/issue-54516.rs b/src/test/ui/type/ascription/issue-54516.rs index b53bfe5df03..8d6fd2abb6d 100644 --- a/src/test/ui/type/ascription/issue-54516.rs +++ b/src/test/ui/type/ascription/issue-54516.rs @@ -2,5 +2,7 @@ use std::collections::BTreeMap; fn main() { println!("{}", std::mem:size_of::>()); - //~^ ERROR expected one of + //~^ ERROR casts cannot be followed by a function call + //~| ERROR expected value, found module `std::mem` [E0423] + //~| ERROR cannot find type `size_of` in this scope [E0412] } diff --git a/src/test/ui/type/ascription/issue-54516.stderr b/src/test/ui/type/ascription/issue-54516.stderr index 7127f67cd7d..fdf35700ef9 100644 --- a/src/test/ui/type/ascription/issue-54516.stderr +++ b/src/test/ui/type/ascription/issue-54516.stderr @@ -1,13 +1,31 @@ -error: expected one of `!`, `,`, or `::`, found `(` - --> $DIR/issue-54516.rs:4:58 +error: casts cannot be followed by a function call + --> $DIR/issue-54516.rs:4:20 | LL | println!("{}", std::mem:size_of::>()); - | - ^ expected one of `!`, `,`, or `::` + | ^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` = note: see issue #23416 for more information -error: aborting due to previous error +error[E0423]: expected value, found module `std::mem` + --> $DIR/issue-54516.rs:4:20 + | +LL | println!("{}", std::mem:size_of::>()); + | ^^^^^^^^- help: maybe you meant to write a path separator here: `::` + | | + | not a value + +error[E0412]: cannot find type `size_of` in this scope + --> $DIR/issue-54516.rs:4:29 + | +LL | println!("{}", std::mem:size_of::>()); + | -^^^^^^^ not found in this scope + | | + | help: maybe you meant to write a path separator here: `::` + +error: aborting due to 3 previous errors +Some errors have detailed explanations: E0412, E0423. +For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/type/ascription/issue-60933.rs b/src/test/ui/type/ascription/issue-60933.rs index 8fb06c887bd..bcf9f88cb41 100644 --- a/src/test/ui/type/ascription/issue-60933.rs +++ b/src/test/ui/type/ascription/issue-60933.rs @@ -1,4 +1,6 @@ fn main() { let u: usize = std::mem:size_of::(); - //~^ ERROR expected one of + //~^ ERROR casts cannot be followed by a function call + //~| ERROR expected value, found module `std::mem` [E0423] + //~| ERROR cannot find type `size_of` in this scope [E0412] } diff --git a/src/test/ui/type/ascription/issue-60933.stderr b/src/test/ui/type/ascription/issue-60933.stderr index 7130767b6c6..cd9ae8f49f4 100644 --- a/src/test/ui/type/ascription/issue-60933.stderr +++ b/src/test/ui/type/ascription/issue-60933.stderr @@ -1,13 +1,31 @@ -error: expected one of `!`, `::`, or `;`, found `(` - --> $DIR/issue-60933.rs:2:43 +error: casts cannot be followed by a function call + --> $DIR/issue-60933.rs:2:20 | LL | let u: usize = std::mem:size_of::(); - | - ^ expected one of `!`, `::`, or `;` + | ^^^^^^^^-^^^^^^^^^^^^^^ | | | help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` = note: see issue #23416 for more information -error: aborting due to previous error +error[E0423]: expected value, found module `std::mem` + --> $DIR/issue-60933.rs:2:20 + | +LL | let u: usize = std::mem:size_of::(); + | ^^^^^^^^- help: maybe you meant to write a path separator here: `::` + | | + | not a value + +error[E0412]: cannot find type `size_of` in this scope + --> $DIR/issue-60933.rs:2:29 + | +LL | let u: usize = std::mem:size_of::(); + | -^^^^^^^ not found in this scope + | | + | help: maybe you meant to write a path separator here: `::` + +error: aborting due to 3 previous errors +Some errors have detailed explanations: E0412, E0423. +For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/type/type-ascription-instead-of-initializer.rs b/src/test/ui/type/type-ascription-instead-of-initializer.rs index aef25250b15..9f9b6f06bbc 100644 --- a/src/test/ui/type/type-ascription-instead-of-initializer.rs +++ b/src/test/ui/type/type-ascription-instead-of-initializer.rs @@ -1,4 +1,4 @@ fn main() { let x: Vec::with_capacity(10, 20); //~ ERROR expected type, found `10` - //~^ ERROR this function takes 1 parameter + //~^ ERROR this function takes 1 argument } diff --git a/src/test/ui/type/type-ascription-instead-of-initializer.stderr b/src/test/ui/type/type-ascription-instead-of-initializer.stderr index 3fe676de59d..530f77e5ae9 100644 --- a/src/test/ui/type/type-ascription-instead-of-initializer.stderr +++ b/src/test/ui/type/type-ascription-instead-of-initializer.stderr @@ -7,11 +7,13 @@ LL | let x: Vec::with_capacity(10, 20); | |help: use `=` if you meant to assign | while parsing the type for `x` -error[E0061]: this function takes 1 parameter but 2 parameters were supplied +error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/type-ascription-instead-of-initializer.rs:2:12 | LL | let x: Vec::with_capacity(10, 20); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 parameter + | ^^^^^^^^^^^^^^^^^^ -- -- supplied 2 arguments + | | + | expected 1 argument error: aborting due to 2 previous errors diff --git a/src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.rs b/src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.rs index c57e8149574..7bf151514c3 100644 --- a/src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.rs +++ b/src/test/ui/typeck/issue-52082-type-param-shadows-existing-type.rs @@ -1,4 +1,4 @@ -// Fix issue 52082: Confusing error if accidentially defining a type paramter with the same name as +// Fix issue 52082: Confusing error if accidentally defining a type parameter with the same name as // an existing type // // To this end, make sure that when trying to retrieve a field of a (reference to) type parameter, diff --git a/src/test/ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.rs b/src/test/ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.rs new file mode 100644 index 00000000000..571692a5374 --- /dev/null +++ b/src/test/ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.rs @@ -0,0 +1,9 @@ +// Regression test for #69378: no type for node after struct parse recovery + +struct Foo { 0: u8 } //~ ERROR expected identifier + +fn test(f: Foo) { + Foo{foo: 4, ..f}; +} + +fn main() {} diff --git a/src/test/ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.stderr b/src/test/ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.stderr new file mode 100644 index 00000000000..6bc9c8498c9 --- /dev/null +++ b/src/test/ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `0` + --> $DIR/issue-69378-ice-on-invalid-type-node-after-recovery.rs:3:14 + | +LL | struct Foo { 0: u8 } + | ^ expected identifier + +error: aborting due to previous error + diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr b/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr index 8755bcded9d..e3976293277 100644 --- a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr +++ b/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr @@ -1,8 +1,10 @@ error[E0568]: auto traits cannot have super traits - --> $DIR/typeck-auto-trait-no-supertraits-2.rs:3:1 + --> $DIR/typeck-auto-trait-no-supertraits-2.rs:3:20 | LL | auto trait Magic : Sized where Option : Magic {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----- ^^^^^ help: remove the super traits + | | + | auto trait cannot have super traits error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr b/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr index 5a388834909..b1602e3642e 100644 --- a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr +++ b/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr @@ -1,8 +1,10 @@ error[E0568]: auto traits cannot have super traits - --> $DIR/typeck-auto-trait-no-supertraits.rs:27:1 + --> $DIR/typeck-auto-trait-no-supertraits.rs:27:19 | LL | auto trait Magic: Copy {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----- ^^^^ help: remove the super traits + | | + | auto trait cannot have super traits error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs index 86c7c52b271..6cd2b8c75b6 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.rs +++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs @@ -1,4 +1,5 @@ -#![feature(type_alias_impl_trait)] // Needed for single test `type Y = impl Trait<_>` +// Needed for `type Y = impl Trait<_>` and `type B = _;` +#![feature(type_alias_impl_trait, associated_type_defaults)] // This test checks that it is not possible to enable global type // inference by using the `_` type placeholder. @@ -157,9 +158,12 @@ trait BadTrait<_> {} //~^ ERROR expected identifier, found reserved identifier `_` impl BadTrait<_> for BadStruct<_> {} //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures fn impl_trait() -> impl BadTrait<_> { //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures unimplemented!() } @@ -174,12 +178,36 @@ struct BadStruct2<_, T>(_, T); type X = Box<_>; //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures struct Struct; trait Trait {} impl Trait for Struct {} type Y = impl Trait<_>; //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~| ERROR the type placeholder `_` is not allowed within types on item signatures fn foo() -> Y { Struct } + +trait Qux { + type A; + type B = _; + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + const C: _; + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + const D: _ = 42; + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + // type E: _; // FIXME: make the parser propagate the existence of `B` +} +impl Qux for Struct { + type A = _; + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + type B = _; + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + const C: _; + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~| ERROR associated constant in `impl` without body + const D: _ = 42; + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +} diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index 95e8f94c6f3..dc86ab30dfe 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -1,35 +1,43 @@ error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:153:18 + --> $DIR/typeck_type_placeholder_item.rs:154:18 | LL | struct BadStruct<_>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:156:16 + --> $DIR/typeck_type_placeholder_item.rs:157:16 | LL | trait BadTrait<_> {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:166:19 + --> $DIR/typeck_type_placeholder_item.rs:170:19 | LL | struct BadStruct1<_, _>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:166:22 + --> $DIR/typeck_type_placeholder_item.rs:170:22 | LL | struct BadStruct1<_, _>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:171:19 + --> $DIR/typeck_type_placeholder_item.rs:175:19 | LL | struct BadStruct2<_, T>(_, T); | ^ expected identifier, found reserved identifier +error: associated constant in `impl` without body + --> $DIR/typeck_type_placeholder_item.rs:208:5 + | +LL | const C: _; + | ^^^^^^^^^^- + | | + | help: provide a definition for the constant: `= ;` + error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters - --> $DIR/typeck_type_placeholder_item.rs:166:22 + --> $DIR/typeck_type_placeholder_item.rs:170:22 | LL | struct BadStruct1<_, _>(_); | - ^ already used @@ -37,7 +45,7 @@ LL | struct BadStruct1<_, _>(_); | first use of `_` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:5:14 + --> $DIR/typeck_type_placeholder_item.rs:6:14 | LL | fn test() -> _ { 5 } | ^ @@ -46,7 +54,7 @@ LL | fn test() -> _ { 5 } | help: replace with the correct return type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:8:16 + --> $DIR/typeck_type_placeholder_item.rs:9:16 | LL | fn test2() -> (_, _) { (5, 5) } | -^--^- @@ -56,16 +64,16 @@ LL | fn test2() -> (_, _) { (5, 5) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:11:15 + --> $DIR/typeck_type_placeholder_item.rs:12:15 | LL | static TEST3: _ = "test"; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `&'static str` + | help: replace `_` with the correct type: `&str` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:14:15 + --> $DIR/typeck_type_placeholder_item.rs:15:15 | LL | static TEST4: _ = 145; | ^ @@ -74,13 +82,13 @@ LL | static TEST4: _ = 145; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:17:15 + --> $DIR/typeck_type_placeholder_item.rs:18:15 | LL | static TEST5: (_, _) = (1, 2); | ^^^^^^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:20:13 + --> $DIR/typeck_type_placeholder_item.rs:21:13 | LL | fn test6(_: _) { } | ^ not allowed in type signatures @@ -91,7 +99,7 @@ LL | fn test6(_: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:23:18 + --> $DIR/typeck_type_placeholder_item.rs:24:18 | LL | fn test6_b(_: _, _: T) { } | ^ not allowed in type signatures @@ -102,7 +110,7 @@ LL | fn test6_b(_: K, _: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:26:30 + --> $DIR/typeck_type_placeholder_item.rs:27:30 | LL | fn test6_c(_: _, _: (T, K, L, A, B)) { } | ^ not allowed in type signatures @@ -113,7 +121,7 @@ LL | fn test6_c(_: C, _: (T, K, L, A, B)) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:29:13 + --> $DIR/typeck_type_placeholder_item.rs:30:13 | LL | fn test7(x: _) { let _x: usize = x; } | ^ not allowed in type signatures @@ -124,13 +132,13 @@ LL | fn test7(x: T) { let _x: usize = x; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:32:22 + --> $DIR/typeck_type_placeholder_item.rs:33:22 | LL | fn test8(_f: fn() -> _) { } | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:32:22 + --> $DIR/typeck_type_placeholder_item.rs:33:22 | LL | fn test8(_f: fn() -> _) { } | ^ not allowed in type signatures @@ -141,7 +149,7 @@ LL | fn test8(_f: fn() -> T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:46:26 + --> $DIR/typeck_type_placeholder_item.rs:47:26 | LL | fn test11(x: &usize) -> &_ { | -^ @@ -150,7 +158,7 @@ LL | fn test11(x: &usize) -> &_ { | help: replace with the correct return type: `&&usize` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:51:52 + --> $DIR/typeck_type_placeholder_item.rs:52:52 | LL | unsafe fn test12(x: *const usize) -> *const *const _ { | --------------^ @@ -159,7 +167,7 @@ LL | unsafe fn test12(x: *const usize) -> *const *const _ { | help: replace with the correct return type: `*const *const usize` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:65:8 + --> $DIR/typeck_type_placeholder_item.rs:66:8 | LL | a: _, | ^ not allowed in type signatures @@ -178,13 +186,13 @@ LL | b: (T, T), | error: missing type for `static` item - --> $DIR/typeck_type_placeholder_item.rs:71:12 + --> $DIR/typeck_type_placeholder_item.rs:72:12 | LL | static A = 42; | ^ help: provide a type for the item: `A: i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:73:15 + --> $DIR/typeck_type_placeholder_item.rs:74:15 | LL | static B: _ = 42; | ^ @@ -193,13 +201,13 @@ LL | static B: _ = 42; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:75:15 + --> $DIR/typeck_type_placeholder_item.rs:76:15 | LL | static C: Option<_> = Some(42); | ^^^^^^^^^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:78:21 + --> $DIR/typeck_type_placeholder_item.rs:79:21 | LL | fn fn_test() -> _ { 5 } | ^ @@ -208,7 +216,7 @@ LL | fn fn_test() -> _ { 5 } | help: replace with the correct return type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:81:23 + --> $DIR/typeck_type_placeholder_item.rs:82:23 | LL | fn fn_test2() -> (_, _) { (5, 5) } | -^--^- @@ -218,16 +226,16 @@ LL | fn fn_test2() -> (_, _) { (5, 5) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:84:22 + --> $DIR/typeck_type_placeholder_item.rs:85:22 | LL | static FN_TEST3: _ = "test"; | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `&'static str` + | help: replace `_` with the correct type: `&str` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:87:22 + --> $DIR/typeck_type_placeholder_item.rs:88:22 | LL | static FN_TEST4: _ = 145; | ^ @@ -236,13 +244,13 @@ LL | static FN_TEST4: _ = 145; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:90:22 + --> $DIR/typeck_type_placeholder_item.rs:91:22 | LL | static FN_TEST5: (_, _) = (1, 2); | ^^^^^^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:93:20 + --> $DIR/typeck_type_placeholder_item.rs:94:20 | LL | fn fn_test6(_: _) { } | ^ not allowed in type signatures @@ -253,7 +261,7 @@ LL | fn fn_test6(_: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:96:20 + --> $DIR/typeck_type_placeholder_item.rs:97:20 | LL | fn fn_test7(x: _) { let _x: usize = x; } | ^ not allowed in type signatures @@ -264,13 +272,13 @@ LL | fn fn_test7(x: T) { let _x: usize = x; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:99:29 + --> $DIR/typeck_type_placeholder_item.rs:100:29 | LL | fn fn_test8(_f: fn() -> _) { } | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:99:29 + --> $DIR/typeck_type_placeholder_item.rs:100:29 | LL | fn fn_test8(_f: fn() -> _) { } | ^ not allowed in type signatures @@ -281,7 +289,7 @@ LL | fn fn_test8(_f: fn() -> T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:122:12 + --> $DIR/typeck_type_placeholder_item.rs:123:12 | LL | a: _, | ^ not allowed in type signatures @@ -300,13 +308,13 @@ LL | b: (T, T), | error[E0282]: type annotations needed - --> $DIR/typeck_type_placeholder_item.rs:127:18 + --> $DIR/typeck_type_placeholder_item.rs:128:18 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } | ^ cannot infer type error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:127:28 + --> $DIR/typeck_type_placeholder_item.rs:128:28 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } | ^ ^ not allowed in type signatures @@ -314,7 +322,7 @@ LL | fn fn_test11(_: _) -> (_, _) { panic!() } | not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:131:30 + --> $DIR/typeck_type_placeholder_item.rs:132:30 | LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } | -^--^- @@ -324,7 +332,7 @@ LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:134:33 + --> $DIR/typeck_type_placeholder_item.rs:135:33 | LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | ------^- @@ -333,7 +341,7 @@ LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:153:21 + --> $DIR/typeck_type_placeholder_item.rs:154:21 | LL | struct BadStruct<_>(_); | ^ not allowed in type signatures @@ -344,7 +352,19 @@ LL | struct BadStruct(T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:158:15 + --> $DIR/typeck_type_placeholder_item.rs:159:32 + | +LL | impl BadTrait<_> for BadStruct<_> {} + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:159:15 + | +LL | impl BadTrait<_> for BadStruct<_> {} + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:159:15 | LL | impl BadTrait<_> for BadStruct<_> {} | ^ ^ not allowed in type signatures @@ -357,13 +377,13 @@ LL | impl BadTrait for BadStruct {} | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:161:34 + --> $DIR/typeck_type_placeholder_item.rs:164:34 | LL | fn impl_trait() -> impl BadTrait<_> { | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:166:25 + --> $DIR/typeck_type_placeholder_item.rs:170:25 | LL | struct BadStruct1<_, _>(_); | ^ not allowed in type signatures @@ -374,7 +394,7 @@ LL | struct BadStruct1(T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:171:25 + --> $DIR/typeck_type_placeholder_item.rs:175:25 | LL | struct BadStruct2<_, T>(_, T); | ^ not allowed in type signatures @@ -385,13 +405,19 @@ LL | struct BadStruct2(K, T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:175:14 + --> $DIR/typeck_type_placeholder_item.rs:179:14 | LL | type X = Box<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:42:27 + --> $DIR/typeck_type_placeholder_item.rs:179:14 + | +LL | type X = Box<_>; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:43:27 | LL | fn test10(&self, _x : _) { } | ^ not allowed in type signatures @@ -402,7 +428,7 @@ LL | fn test10(&self, _x : T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:139:31 + --> $DIR/typeck_type_placeholder_item.rs:140:31 | LL | fn method_test1(&self, x: _); | ^ not allowed in type signatures @@ -413,7 +439,7 @@ LL | fn method_test1(&self, x: T); | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:141:31 + --> $DIR/typeck_type_placeholder_item.rs:142:31 | LL | fn method_test2(&self, x: _) -> _; | ^ ^ not allowed in type signatures @@ -426,7 +452,7 @@ LL | fn method_test2(&self, x: T) -> T; | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:143:31 + --> $DIR/typeck_type_placeholder_item.rs:144:31 | LL | fn method_test3(&self) -> _; | ^ not allowed in type signatures @@ -437,7 +463,7 @@ LL | fn method_test3(&self) -> T; | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:145:26 + --> $DIR/typeck_type_placeholder_item.rs:146:26 | LL | fn assoc_fn_test1(x: _); | ^ not allowed in type signatures @@ -448,7 +474,7 @@ LL | fn assoc_fn_test1(x: T); | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:147:26 + --> $DIR/typeck_type_placeholder_item.rs:148:26 | LL | fn assoc_fn_test2(x: _) -> _; | ^ ^ not allowed in type signatures @@ -461,7 +487,7 @@ LL | fn assoc_fn_test2(x: T) -> T; | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:149:28 + --> $DIR/typeck_type_placeholder_item.rs:150:28 | LL | fn assoc_fn_test3() -> _; | ^ not allowed in type signatures @@ -472,7 +498,7 @@ LL | fn assoc_fn_test3() -> T; | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:60:37 + --> $DIR/typeck_type_placeholder_item.rs:61:37 | LL | fn clone_from(&mut self, other: _) { *self = Test9; } | ^ not allowed in type signatures @@ -483,7 +509,7 @@ LL | fn clone_from(&mut self, other: T) { *self = Test9; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:109:34 + --> $DIR/typeck_type_placeholder_item.rs:110:34 | LL | fn fn_test10(&self, _x : _) { } | ^ not allowed in type signatures @@ -494,7 +520,7 @@ LL | fn fn_test10(&self, _x : T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:117:41 + --> $DIR/typeck_type_placeholder_item.rs:118:41 | LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } | ^ not allowed in type signatures @@ -505,13 +531,46 @@ LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:181:21 + --> $DIR/typeck_type_placeholder_item.rs:164:34 + | +LL | fn impl_trait() -> impl BadTrait<_> { + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:186:21 + | +LL | type Y = impl Trait<_>; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:186:21 | LL | type Y = impl Trait<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:39:24 + --> $DIR/typeck_type_placeholder_item.rs:195:14 + | +LL | type B = _; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:197:14 + | +LL | const C: _; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:199:14 + | +LL | const D: _ = 42; + | ^ + | | + | not allowed in type signatures + | help: replace `_` with the correct type: `i32` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:40:24 | LL | fn test9(&self) -> _ { () } | ^ @@ -520,7 +579,7 @@ LL | fn test9(&self) -> _ { () } | help: replace with the correct return type: `()` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:57:24 + --> $DIR/typeck_type_placeholder_item.rs:58:24 | LL | fn clone(&self) -> _ { Test9 } | ^ @@ -529,7 +588,7 @@ LL | fn clone(&self) -> _ { Test9 } | help: replace with the correct return type: `Test9` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:106:31 + --> $DIR/typeck_type_placeholder_item.rs:107:31 | LL | fn fn_test9(&self) -> _ { () } | ^ @@ -538,7 +597,7 @@ LL | fn fn_test9(&self) -> _ { () } | help: replace with the correct return type: `()` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:114:28 + --> $DIR/typeck_type_placeholder_item.rs:115:28 | LL | fn clone(&self) -> _ { FnTest9 } | ^ @@ -546,7 +605,34 @@ LL | fn clone(&self) -> _ { FnTest9 } | not allowed in type signatures | help: replace with the correct return type: `main::FnTest9` -error: aborting due to 58 previous errors +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:204:14 + | +LL | type A = _; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:206:14 + | +LL | type B = _; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:208:14 + | +LL | const C: _; + | ^ not allowed in type signatures + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:211:14 + | +LL | const D: _ = 42; + | ^ + | | + | not allowed in type signatures + | help: replace `_` with the correct type: `i32` + +error: aborting due to 71 previous errors Some errors have detailed explanations: E0121, E0282, E0403. For more information about an error, try `rustc --explain E0121`. diff --git a/src/test/ui/ufcs/ufcs-partially-resolved.rs b/src/test/ui/ufcs/ufcs-partially-resolved.rs index 66d4db3ebaf..e6470aa6d64 100644 --- a/src/test/ui/ufcs/ufcs-partially-resolved.rs +++ b/src/test/ui/ufcs/ufcs-partially-resolved.rs @@ -35,7 +35,7 @@ fn main() { ::N::NN; //~ ERROR cannot find associated type `N` in `A` let _: ::Y::NN; //~ ERROR ambiguous associated type let _: ::Y::NN; //~ ERROR expected associated type, found variant `E::Y` - ::Y::NN; //~ ERROR no associated item named `NN` found + ::Y::NN; //~ ERROR no associated item named `NN` found for type `u16` ::Y::NN; //~ ERROR expected associated type, found variant `E::Y` let _: ::NN; //~ ERROR cannot find associated type `NN` in `Tr::N` @@ -49,8 +49,8 @@ fn main() { ::NN; //~ ERROR cannot find method or associated constant `NN` in `Tr::Y` ::NN; //~ ERROR failed to resolve: `Y` is a variant, not a module - let _: ::Z; //~ ERROR expected associated type, found method `Dr::Z` + let _: ::Z; //~ ERROR expected associated type, found associated function `Dr::Z` ::X; //~ ERROR expected method or associated constant, found associated type `Dr::X` - let _: ::Z::N; //~ ERROR expected associated type, found method `Dr::Z` - ::X::N; //~ ERROR no associated item named `N` found + let _: ::Z::N; //~ ERROR expected associated type, found associated function `Dr::Z` + ::X::N; //~ ERROR no associated item named `N` found for type `u16` } diff --git a/src/test/ui/ufcs/ufcs-partially-resolved.stderr b/src/test/ui/ufcs/ufcs-partially-resolved.stderr index 60ebe8ee053..7177ca49085 100644 --- a/src/test/ui/ufcs/ufcs-partially-resolved.stderr +++ b/src/test/ui/ufcs/ufcs-partially-resolved.stderr @@ -35,10 +35,10 @@ error[E0576]: cannot find method or associated constant `N` in trait `Tr` --> $DIR/ufcs-partially-resolved.rs:22:17 | LL | fn Y() {} - | --------- similarly named method `Y` defined here + | --------- similarly named associated function `Y` defined here ... LL | ::N; - | ^ help: a method with a similar name exists: `Y` + | ^ help: an associated function with a similar name exists: `Y` error[E0576]: cannot find method or associated constant `N` in enum `E` --> $DIR/ufcs-partially-resolved.rs:23:16 @@ -166,7 +166,7 @@ error[E0576]: cannot find method or associated constant `NN` in `Tr::Y` LL | ::NN; | ^^ not found in `Tr::Y` -error[E0575]: expected associated type, found method `Dr::Z` +error[E0575]: expected associated type, found associated function `Dr::Z` --> $DIR/ufcs-partially-resolved.rs:52:12 | LL | type X = u16; @@ -181,16 +181,16 @@ error[E0575]: expected method or associated constant, found associated type `Dr: --> $DIR/ufcs-partially-resolved.rs:53:5 | LL | fn Z() {} - | --------- similarly named method `Z` defined here + | --------- similarly named associated function `Z` defined here ... LL | ::X; | ^^^^^^^^^^^^- | | - | help: a method with a similar name exists: `Z` + | help: an associated function with a similar name exists: `Z` | = note: can't use a type alias as a constructor -error[E0575]: expected associated type, found method `Dr::Z` +error[E0575]: expected associated type, found associated function `Dr::Z` --> $DIR/ufcs-partially-resolved.rs:54:12 | LL | type X = u16; @@ -205,19 +205,19 @@ error[E0223]: ambiguous associated type --> $DIR/ufcs-partially-resolved.rs:36:12 | LL | let _: ::Y::NN; - | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<::Y as Trait>::NN` + | ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::NN` -error[E0599]: no associated item named `NN` found for associated type `::Y` in the current scope +error[E0599]: no associated item named `NN` found for type `u16` in the current scope --> $DIR/ufcs-partially-resolved.rs:38:20 | LL | ::Y::NN; - | ^^ associated item not found in `::Y` + | ^^ associated item not found in `u16` -error[E0599]: no associated item named `N` found for associated type `::X` in the current scope +error[E0599]: no associated item named `N` found for type `u16` in the current scope --> $DIR/ufcs-partially-resolved.rs:55:20 | LL | ::X::N; - | ^ associated item not found in `::X` + | ^ associated item not found in `u16` error: aborting due to 32 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unique-type-id.rs b/src/test/ui/unboxed-closures/unboxed-closures-unique-type-id.rs index 5d1e00d2d35..9c6be50c5c7 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-unique-type-id.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-unique-type-id.rs @@ -4,7 +4,7 @@ // // error: internal compiler error: get_unique_type_id_of_type() - // unexpected type: closure, -// Closure(syntax::ast::DefId{krate: 0, node: 66}, +// Closure(rustc_ast::ast::DefId{krate: 0, node: 66}, // ReScope(63)) // // This is a regression test for issue #17021. diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr index 12b5321331a..01c8e8471aa 100644 --- a/src/test/ui/union/union-derive-clone.stderr +++ b/src/test/ui/union/union-derive-clone.stderr @@ -11,16 +11,20 @@ error[E0599]: no method named `clone` found for union `U5` in the c --> $DIR/union-derive-clone.rs:37:15 | LL | union U5 { - | ----------- method `clone` not found for this + | ----------- + | | + | method `clone` not found for this + | doesn't satisfy `U5: std::clone::Clone` +... +LL | struct CloneNoCopy; + | ------------------- doesn't satisfy `CloneNoCopy: std::marker::Copy` ... LL | let w = u.clone(); | ^^^^^ method not found in `U5` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `U5 : std::clone::Clone` - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `std::clone::Clone` + `CloneNoCopy: std::marker::Copy` + which is required by `U5: std::clone::Clone` error: aborting due to 2 previous errors diff --git a/src/test/ui/unique-object-noncopyable.rs b/src/test/ui/unique-object-noncopyable.rs index dd38a7190aa..bedaf27c2dd 100644 --- a/src/test/ui/unique-object-noncopyable.rs +++ b/src/test/ui/unique-object-noncopyable.rs @@ -1,3 +1,7 @@ +// FIXME: missing sysroot spans (#53081) +// ignore-i586-unknown-linux-gnu +// ignore-i586-unknown-linux-musl +// ignore-i686-unknown-linux-musl #![feature(box_syntax)] trait Foo { diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 92cda6482c0..fb78095224b 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -1,14 +1,25 @@ error[E0599]: no method named `clone` found for struct `std::boxed::Box` in the current scope - --> $DIR/unique-object-noncopyable.rs:24:16 + --> $DIR/unique-object-noncopyable.rs:28:16 | +LL | trait Foo { + | --------- + | | + | doesn't satisfy `dyn Foo: std::clone::Clone` + | doesn't satisfy `dyn Foo: std::marker::Sized` +... LL | let _z = y.clone(); | ^^^^^ method not found in `std::boxed::Box` + | + ::: $SRC_DIR/liballoc/boxed.rs:LL:COL + | +LL | pub struct Box(Unique); + | ------------------------------------- doesn't satisfy `std::boxed::Box: std::clone::Clone` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `std::boxed::Box : std::clone::Clone` - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `clone`, perhaps you need to implement it: - candidate #1: `std::clone::Clone` + `dyn Foo: std::marker::Sized` + which is required by `std::boxed::Box: std::clone::Clone` + `dyn Foo: std::clone::Clone` + which is required by `std::boxed::Box: std::clone::Clone` error: aborting due to previous error diff --git a/src/test/ui/unique-pinned-nocopy.rs b/src/test/ui/unique-pinned-nocopy.rs index 4c30450c704..091b8a43862 100644 --- a/src/test/ui/unique-pinned-nocopy.rs +++ b/src/test/ui/unique-pinned-nocopy.rs @@ -1,3 +1,7 @@ +// FIXME: missing sysroot spans (#53081) +// ignore-i586-unknown-linux-gnu +// ignore-i586-unknown-linux-musl +// ignore-i686-unknown-linux-musl #[derive(Debug)] struct R { b: bool, diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index e5c3eaccbd3..ea6575d1d85 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -1,11 +1,20 @@ error[E0599]: no method named `clone` found for struct `std::boxed::Box` in the current scope - --> $DIR/unique-pinned-nocopy.rs:12:16 + --> $DIR/unique-pinned-nocopy.rs:16:16 | +LL | struct R { + | -------- doesn't satisfy `R: std::clone::Clone` +... LL | let _j = i.clone(); | ^^^^^ method not found in `std::boxed::Box` + | + ::: $SRC_DIR/liballoc/boxed.rs:LL:COL + | +LL | pub struct Box(Unique); + | ------------------------------------- doesn't satisfy `std::boxed::Box: std::clone::Clone` | = note: the method `clone` exists but the following trait bounds were not satisfied: - `std::boxed::Box : std::clone::Clone` + `R: std::clone::Clone` + which is required by `std::boxed::Box: std::clone::Clone` = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `std::clone::Clone` diff --git a/src/test/ui/unop-neg-bool.stderr b/src/test/ui/unop-neg-bool.stderr index 18273013749..9913747b88e 100644 --- a/src/test/ui/unop-neg-bool.stderr +++ b/src/test/ui/unop-neg-bool.stderr @@ -3,8 +3,6 @@ error[E0600]: cannot apply unary operator `-` to type `bool` | LL | -true; | ^^^^^ cannot apply unary operator `-` - | - = note: an implementation of `std::ops::Neg` might be missing for `bool` error: aborting due to previous error diff --git a/src/test/ui/unsafe/unsafe-block-without-braces.stderr b/src/test/ui/unsafe/unsafe-block-without-braces.stderr index 13e0c3681fa..895f33638f9 100644 --- a/src/test/ui/unsafe/unsafe-block-without-braces.stderr +++ b/src/test/ui/unsafe/unsafe-block-without-braces.stderr @@ -1,10 +1,11 @@ error: expected `{`, found `std` --> $DIR/unsafe-block-without-braces.rs:3:9 | -LL | unsafe //{ - | - expected `{` LL | std::mem::transmute::(1.0); - | ^^^ unexpected token + | ^^^---------------------------------- + | | + | expected `{` + | help: try placing this code inside a block: `{ std::mem::transmute::(1.0); }` error: aborting due to previous error diff --git a/src/test/ui/useless-comment.stderr b/src/test/ui/useless-comment.stderr index e5e4290d0e1..92817321a88 100644 --- a/src/test/ui/useless-comment.stderr +++ b/src/test/ui/useless-comment.stderr @@ -2,9 +2,7 @@ error: unused doc comment --> $DIR/useless-comment.rs:9:1 | LL | /// foo - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | mac!(); - | ------- rustdoc does not generate documentation for macro expansions + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macros | note: the lint level is defined here --> $DIR/useless-comment.rs:3:9 @@ -13,6 +11,14 @@ LL | #![deny(unused_doc_comments)] | ^^^^^^^^^^^^^^^^^^^ = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion +error: unused doc comment + --> $DIR/useless-comment.rs:32:5 + | +LL | /// bar + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macros + | + = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion + error: unused doc comment --> $DIR/useless-comment.rs:13:5 | @@ -68,16 +74,6 @@ LL | #[doc = "bar"] LL | 3; | - rustdoc does not generate documentation for expressions -error: unused doc comment - --> $DIR/useless-comment.rs:32:5 - | -LL | /// bar - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | mac!(); - | ------- rustdoc does not generate documentation for macro expansions - | - = help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion - error: unused doc comment --> $DIR/useless-comment.rs:35:13 | diff --git a/src/test/ui/vec/vec-res-add.stderr b/src/test/ui/vec/vec-res-add.stderr index 1cc12a222e5..2d41583268c 100644 --- a/src/test/ui/vec/vec-res-add.stderr +++ b/src/test/ui/vec/vec-res-add.stderr @@ -5,8 +5,6 @@ LL | let k = i + j; | - ^ - std::vec::Vec | | | std::vec::Vec - | - = note: an implementation of `std::ops::Add` might be missing for `std::vec::Vec` error: aborting due to previous error diff --git a/src/test/ui/wf/wf-array-elem-sized.rs b/src/test/ui/wf/wf-array-elem-sized.rs index 41c2d3c43e9..34bf2203426 100644 --- a/src/test/ui/wf/wf-array-elem-sized.rs +++ b/src/test/ui/wf/wf-array-elem-sized.rs @@ -1,4 +1,4 @@ -// Check that array elemen types must be Sized. Issue #25692. +// Check that array element types must be Sized. Issue #25692. #![allow(dead_code)] diff --git a/src/test/ui/wf/wf-impl-associated-type-region.stderr b/src/test/ui/wf/wf-impl-associated-type-region.stderr index 9cc36025305..9942c80effe 100644 --- a/src/test/ui/wf/wf-impl-associated-type-region.stderr +++ b/src/test/ui/wf/wf-impl-associated-type-region.stderr @@ -2,7 +2,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/wf-impl-associated-type-region.rs:10:5 | LL | impl<'a, T> Foo<'a> for T { - | - help: consider adding an explicit lifetime bound `T: 'a`... + | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Bar = &'a T; | ^^^^^^^^^^^^^^^^^ | diff --git a/src/test/ui/wf/wf-in-fn-type-static.stderr b/src/test/ui/wf/wf-in-fn-type-static.stderr index 8952c78aacd..7dc8f5a9661 100644 --- a/src/test/ui/wf/wf-in-fn-type-static.stderr +++ b/src/test/ui/wf/wf-in-fn-type-static.stderr @@ -2,7 +2,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/wf-in-fn-type-static.rs:13:5 | LL | struct Foo { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: 'static LL | x: fn() -> &'static T | ^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/wf-in-fn-type-static.rs:18:5 | LL | struct Bar { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: Copy LL | x: fn(&'static T) | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/wf/wf-in-obj-type-static.stderr b/src/test/ui/wf/wf-in-obj-type-static.stderr index c461da76a25..32c3198d55b 100644 --- a/src/test/ui/wf/wf-in-obj-type-static.stderr +++ b/src/test/ui/wf/wf-in-obj-type-static.stderr @@ -2,7 +2,7 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/wf-in-obj-type-static.rs:14:5 | LL | struct Foo { - | - help: consider adding an explicit lifetime bound `T: 'static`... + | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: 'static LL | x: dyn Object<&'static T> | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr index f1cf514e6b2..52786fb3bca 100644 --- a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr +++ b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr @@ -2,7 +2,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:9:5 | LL | impl<'a, T> Trait<'a, T> for usize { - | - help: consider adding an explicit lifetime bound `T: 'a`... + | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = &'a fn(T); | ^^^^^^^^^^^^^^^^^^^^^ | @@ -16,7 +16,7 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:19:5 | LL | impl<'a, T> Trait<'a, T> for u32 { - | - help: consider adding an explicit lifetime bound `T: 'a`... + | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = &'a dyn Baz; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/src/test/ui/xc-private-method.rs b/src/test/ui/xc-private-method.rs index e95cab93d75..f05994646b3 100644 --- a/src/test/ui/xc-private-method.rs +++ b/src/test/ui/xc-private-method.rs @@ -4,8 +4,8 @@ extern crate xc_private_method_lib; fn main() { let _ = xc_private_method_lib::Struct::static_meth_struct(); - //~^ ERROR: method `static_meth_struct` is private + //~^ ERROR: associated function `static_meth_struct` is private let _ = xc_private_method_lib::Enum::static_meth_enum(); - //~^ ERROR: method `static_meth_enum` is private + //~^ ERROR: associated function `static_meth_enum` is private } diff --git a/src/test/ui/xc-private-method.stderr b/src/test/ui/xc-private-method.stderr index 91bec2551c1..6a68bef90ef 100644 --- a/src/test/ui/xc-private-method.stderr +++ b/src/test/ui/xc-private-method.stderr @@ -1,10 +1,10 @@ -error[E0624]: method `static_meth_struct` is private +error[E0624]: associated function `static_meth_struct` is private --> $DIR/xc-private-method.rs:6:13 | LL | let _ = xc_private_method_lib::Struct::static_meth_struct(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0624]: method `static_meth_enum` is private +error[E0624]: associated function `static_meth_enum` is private --> $DIR/xc-private-method.rs:9:13 | LL | let _ = xc_private_method_lib::Enum::static_meth_enum(); diff --git a/src/test/ui/xc-private-method2.rs b/src/test/ui/xc-private-method2.rs index f11b251082b..92946923f6e 100644 --- a/src/test/ui/xc-private-method2.rs +++ b/src/test/ui/xc-private-method2.rs @@ -4,8 +4,8 @@ extern crate xc_private_method_lib; fn main() { let _ = xc_private_method_lib::Struct{ x: 10 }.meth_struct(); - //~^ ERROR method `meth_struct` is private + //~^ ERROR associated function `meth_struct` is private let _ = xc_private_method_lib::Enum::Variant1(20).meth_enum(); - //~^ ERROR method `meth_enum` is private + //~^ ERROR associated function `meth_enum` is private } diff --git a/src/test/ui/xc-private-method2.stderr b/src/test/ui/xc-private-method2.stderr index 36ad850fb19..84a8b9817c0 100644 --- a/src/test/ui/xc-private-method2.stderr +++ b/src/test/ui/xc-private-method2.stderr @@ -1,10 +1,10 @@ -error[E0624]: method `meth_struct` is private +error[E0624]: associated function `meth_struct` is private --> $DIR/xc-private-method2.rs:6:52 | LL | let _ = xc_private_method_lib::Struct{ x: 10 }.meth_struct(); | ^^^^^^^^^^^ -error[E0624]: method `meth_enum` is private +error[E0624]: associated function `meth_enum` is private --> $DIR/xc-private-method2.rs:9:55 | LL | let _ = xc_private_method_lib::Enum::Variant1(20).meth_enum(); diff --git a/src/tools/cargo b/src/tools/cargo index 3c53211c3d7..7019b3ed3d5 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 3c53211c3d7fee4f430f170115af5baad17a3da9 +Subproject commit 7019b3ed3d539db7429d10a343b69be8c426b576 diff --git a/src/tools/clippy b/src/tools/clippy index 07f1736390e..23549a8c362 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 07f1736390e1d4dd88cf9fae4ab7737ee5e086b7 +Subproject commit 23549a8c362a403026432f65a6cb398cb10d44b7 diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index c3d699b3e23..8f685fb8559 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -125,7 +125,7 @@ fn parse_expected( let captures = RE.captures(line)?; match (cfg, captures.name("cfgs")) { - // Only error messages that contain our `cfg` betweeen the square brackets apply to us. + // Only error messages that contain our `cfg` between the square brackets apply to us. (Some(cfg), Some(filter)) if !filter.as_str().split(',').any(|s| s == cfg) => return None, (Some(_), Some(_)) => {} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 555e79d3e06..2a24a8c3c94 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -631,10 +631,6 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, rdr: R, it: &mut dyn let comment = if testfile.to_string_lossy().ends_with(".rs") { "//" } else { "#" }; - // FIXME: would be nice to allow some whitespace between comment and brace :) - // It took me like 2 days to debug why compile-flags weren’t taken into account for my test :) - let comment_with_brace = comment.to_string() + "["; - let mut rdr = BufReader::new(rdr); let mut ln = String::new(); @@ -650,7 +646,7 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, rdr: R, it: &mut dyn let ln = ln.trim(); if ln.starts_with("fn") || ln.starts_with("mod") { return; - } else if ln.starts_with(&comment_with_brace) { + } else if ln.starts_with(comment) && ln[comment.len()..].trim_start().starts_with('[') { // A comment like `//[foo]` is specific to revision `foo` if let Some(close_brace) = ln.find(']') { let open_brace = ln.find('[').unwrap(); @@ -663,10 +659,7 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, rdr: R, it: &mut dyn it(ln[(close_brace + 1)..].trim_start()); } } else { - panic!( - "malformed condition directive: expected `{}foo]`, found `{}`", - comment_with_brace, ln - ) + panic!("malformed condition directive: expected `{}[foo]`, found `{}`", comment, ln) } } else if ln.starts_with(comment) { it(ln[comment.len()..].trim_start()); diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 38fa778219d..6c478f7e29d 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -109,6 +109,24 @@ fn no_system_llvm() { assert!(parse_rs(&config, "// no-system-llvm").ignore); } +#[test] +fn llvm_version() { + let mut config = config(); + + config.llvm_version = Some("8.1.2-rust".to_owned()); + assert!(parse_rs(&config, "// min-llvm-version 9.0").ignore); + + config.llvm_version = Some("9.0.1-rust-1.43.0-dev".to_owned()); + assert!(parse_rs(&config, "// min-llvm-version 9.2").ignore); + + config.llvm_version = Some("9.3.1-rust-1.43.0-dev".to_owned()); + assert!(!parse_rs(&config, "// min-llvm-version 9.2").ignore); + + // FIXME. + // config.llvm_version = Some("10.0.0-rust".to_owned()); + // assert!(!parse_rs(&config, "// min-llvm-version 9.0").ignore); +} + #[test] fn ignore_target() { let mut config = config(); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 690ca8994d8..628fab24fa9 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1479,11 +1479,7 @@ impl<'test> TestCx<'test> { WillExecute::No => TargetLocation::ThisDirectory(self.output_base_dir()), }; - let mut rustc = self.make_compile_args(&self.testpaths.file, output_file, emit_metadata); - - rustc.arg("-L").arg(&self.aux_output_dir_name()); - - match self.config.mode { + let allow_unused = match self.config.mode { CompileFail | Ui => { // compile-fail and ui tests tend to have tons of unused code as // it's just testing various pieces of the compile, but we don't @@ -1492,15 +1488,22 @@ impl<'test> TestCx<'test> { // can turn it back on if needed. if !self.is_rustdoc() // Note that we use the local pass mode here as we don't want - // to set unused to allow if we've overriden the pass mode + // to set unused to allow if we've overridden the pass mode // via command line flags. && local_pm != Some(PassMode::Run) { - rustc.args(&["-A", "unused"]); + AllowUnused::Yes + } else { + AllowUnused::No } } - _ => {} - } + _ => AllowUnused::No, + }; + + let mut rustc = + self.make_compile_args(&self.testpaths.file, output_file, emit_metadata, allow_unused); + + rustc.arg("-L").arg(&self.aux_output_dir_name()); self.compose_and_run_compiler(rustc, None) } @@ -1711,7 +1714,8 @@ impl<'test> TestCx<'test> { // Create the directory for the stdout/stderr files. create_dir_all(aux_cx.output_base_dir()).unwrap(); let input_file = &aux_testpaths.file; - let mut aux_rustc = aux_cx.make_compile_args(input_file, aux_output, EmitMetadata::No); + let mut aux_rustc = + aux_cx.make_compile_args(input_file, aux_output, EmitMetadata::No, AllowUnused::No); let (dylib, crate_type) = if aux_props.no_prefer_dynamic { (true, None) @@ -1820,6 +1824,7 @@ impl<'test> TestCx<'test> { input_file: &Path, output_file: TargetLocation, emit_metadata: EmitMetadata, + allow_unused: AllowUnused, ) -> Command { let is_rustdoc = self.is_rustdoc(); let mut rustc = if !is_rustdoc { @@ -1961,6 +1966,10 @@ impl<'test> TestCx<'test> { rustc.arg("-Ctarget-feature=-crt-static"); } + if let AllowUnused::Yes = allow_unused { + rustc.args(&["-A", "unused"]); + } + rustc.args(&self.props.compile_flags); rustc @@ -2144,7 +2153,8 @@ impl<'test> TestCx<'test> { let output_file = TargetLocation::ThisDirectory(self.output_base_dir()); let input_file = &self.testpaths.file; - let mut rustc = self.make_compile_args(input_file, output_file, EmitMetadata::No); + let mut rustc = + self.make_compile_args(input_file, output_file, EmitMetadata::No, AllowUnused::No); rustc.arg("-L").arg(aux_dir).arg("--emit=llvm-ir"); self.compose_and_run_compiler(rustc, None) @@ -2157,7 +2167,8 @@ impl<'test> TestCx<'test> { let output_file = TargetLocation::ThisFile(output_path.clone()); let input_file = &self.testpaths.file; - let mut rustc = self.make_compile_args(input_file, output_file, EmitMetadata::No); + let mut rustc = + self.make_compile_args(input_file, output_file, EmitMetadata::No, AllowUnused::No); rustc.arg("-L").arg(self.aux_output_dir_name()); @@ -2776,7 +2787,7 @@ impl<'test> TestCx<'test> { Command::new(&nodejs) .arg(root.join("src/tools/rustdoc-js/tester.js")) .arg(out_dir.parent().expect("no parent")) - .arg(&self.testpaths.file.file_stem().expect("couldn't get file stem")), + .arg(self.testpaths.file.with_extension("js")), ); if !res.status.success() { self.fatal_proc_rec("rustdoc-js test failed!", &res); @@ -3008,6 +3019,7 @@ impl<'test> TestCx<'test> { &self.testpaths.file.with_extension(UI_FIXED), TargetLocation::ThisFile(self.make_exe_name()), emit_metadata, + AllowUnused::No, ); rustc.arg("-L").arg(&self.aux_output_dir_name()); let res = self.compose_and_run_compiler(rustc, None); @@ -3200,7 +3212,9 @@ impl<'test> TestCx<'test> { let json = cflags.contains("--error-format json") || cflags.contains("--error-format pretty-json") || cflags.contains("--error-format=json") - || cflags.contains("--error-format=pretty-json"); + || cflags.contains("--error-format=pretty-json") + || cflags.contains("--output-format json") + || cflags.contains("--output-format=json"); let mut normalized = output.to_string(); @@ -3528,6 +3542,11 @@ enum ExpectedLine> { Text(T), } +enum AllowUnused { + Yes, + No, +} + impl fmt::Debug for ExpectedLine where T: AsRef + fmt::Debug, diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 313a303edb2..3335816f09f 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -2,8 +2,8 @@ #![deny(warnings)] extern crate env_logger; +extern crate rustc_ast; extern crate rustc_span; -extern crate syntax; use std::cell::RefCell; use std::collections::BTreeMap; @@ -285,7 +285,7 @@ fn parse_args() -> (OutputFormat, PathBuf) { fn main() { env_logger::init(); let (format, dst) = parse_args(); - let result = syntax::with_default_globals(move || main_with_result(format, &dst)); + let result = rustc_ast::with_default_globals(move || main_with_result(format, &dst)); if let Err(e) = result { panic!("{}", e.to_string()); } diff --git a/src/tools/linkchecker/linkcheck.sh b/src/tools/linkchecker/linkcheck.sh new file mode 100755 index 00000000000..bbccc17e494 --- /dev/null +++ b/src/tools/linkchecker/linkcheck.sh @@ -0,0 +1,113 @@ +#!/bin/sh +# +# This is a script that can be used in each book's CI to validate links using +# the same tool as rust-lang/rust. +# +# This requires the rust-docs rustup component to be installed in the nightly +# toolchain. +# +# Usage: +# ./linkcheck.sh +# +# Options: +# +# -i "Iterative" mode. The script will not clean up after it is done so +# you can inspect the result, and re-run more quickly. +# +# --all Check all books. This can help make sure you don't break links +# from other books into your book. + +set -e + +if [ ! -f book.toml ] && [ ! -f src/SUMMARY.md ] +then + echo "Run command in root directory of the book." + exit 1 +fi + +html_dir="$(rustc +nightly --print sysroot)/share/doc/rust/html" + +if [ ! -d "$html_dir" ] +then + echo "HTML docs are missing from sysroot: $html_dir" + echo "Make sure the nightly rust-docs rustup component is installed." + exit 1 +fi + +book_name="" +# Iterative will avoid cleaning up, so you can quickly run it repeatedly. +iterative=0 +# If "1", test all books, else only this book. +all_books=0 + +while [ "$1" != "" ] +do + case "$1" in + -i) + iterative=1 + ;; + --all) + all_books=1 + ;; + *) + if [ -n "$book_name" ] + then + echo "only one argument allowed" + exit 1 + fi + book_name="$1" + ;; + esac + shift +done + +if [ -z "$book_name" ] +then + echo "usage: $0 " + exit 1 +fi + +if [ ! -d "$html_dir/$book_name" ] +then + echo "book name \"$book_name\" not found in sysroot \"$html_dir\"" + exit 1 +fi + +if [ "$iterative" = "0" ] +then + echo "Cleaning old directories..." + rm -rf linkcheck linkchecker +fi + +if [ ! -e "linkchecker/main.rs" ] || [ "$iterative" = "0" ] +then + echo "Downloading linkchecker source..." + mkdir linkchecker + curl -o linkchecker/Cargo.toml \ + https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/Cargo.toml + curl -o linkchecker/main.rs \ + https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/main.rs +fi + +echo "Building book \"$book_name\"..." +mdbook build + +cp -R "$html_dir" linkcheck +rm -rf "linkcheck/$book_name" +cp -R book "linkcheck/$book_name" + +if [ "$all_books" = "1" ] +then + check_path="linkcheck" +else + check_path="linkcheck/$book_name" +fi +echo "Running linkchecker on \"$check_path\"..." +cargo run --manifest-path=linkchecker/Cargo.toml -- "$check_path" + +if [ "$iterative" = "0" ] +then + rm -rf linkcheck linkchecker +fi + +echo "Link check completed successfully!" diff --git a/src/tools/miri b/src/tools/miri index e3cfb61ece2..0ff05c4cfe5 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit e3cfb61ece273d59b62fb959ed17c99c04941d82 +Subproject commit 0ff05c4cfe534321b194bf3bedf028df92ef519c diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 967333c1ace..b389cd0373c 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -1,11 +1,10 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# This script publishes the new "current" toolstate in the toolstate repo (not to be -# confused with publishing the test results, which happens in -# `src/ci/docker/x86_64-gnu-tools/checktools.sh`). -# It is set as callback for `src/ci/docker/x86_64-gnu-tools/repo.sh` by the CI scripts -# when a new commit lands on `master` (i.e., after it passed all checks on `auto`). +# This script computes the new "current" toolstate for the toolstate repo (not to be +# confused with publishing the test results, which happens in `src/bootstrap/toolstate.rs`). +# It gets called from `src/ci/publish_toolstate.sh` when a new commit lands on `master` +# (i.e., after it passed all checks on `auto`). from __future__ import print_function @@ -131,7 +130,6 @@ def issue( assignees, relevant_pr_number, relevant_pr_user, - pr_reviewer, ): # Open an issue about the toolstate failure. if status == 'test-fail': @@ -147,11 +145,11 @@ def issue( cc @{}, do you think you would have time to do the follow-up work? If so, that would be great! - cc @{}, the PR reviewer, and nominating for compiler team prioritization. + And nominating for compiler team prioritization. ''').format( relevant_pr_number, tool, status_description, - REPOS.get(tool), relevant_pr_user, pr_reviewer + REPOS.get(tool), relevant_pr_user )), 'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number), 'assignees': list(assignees), @@ -211,14 +209,14 @@ def update_latest( if new > old: # things got fixed or at least the status quo improved changed = True - message += '🎉 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \ + message += '🎉 {} on {}: {} → {} (cc {}).\n' \ .format(tool, os, old, new, maintainers) elif new < old: # tests or builds are failing and were not failing before changed = True title = '💔 {} on {}: {} → {}' \ .format(tool, os, old, new) - message += '{} (cc {}, @rust-lang/infra).\n' \ + message += '{} (cc {}).\n' \ .format(title, maintainers) # See if we need to create an issue. if tool == 'miri': @@ -236,7 +234,7 @@ def update_latest( try: issue( tool, create_issue_for_status, MAINTAINERS.get(tool, ''), - relevant_pr_number, relevant_pr_user, pr_reviewer, + relevant_pr_number, relevant_pr_user, ) except urllib2.HTTPError as e: # network errors will simply end up not creating an issue, but that's better diff --git a/src/tools/rls b/src/tools/rls index 0100ac87b4c..5fde462d8c5 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 0100ac87b4ce5bbed6e56a62f313fbc3ff037a89 +Subproject commit 5fde462d8c53b86840100a927a17c8353bba3e3f diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 023f5aa1e28..01f324f0c5a 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -25,6 +25,11 @@ fn main() { .arg_from_usage(d_message) .arg_from_usage(dir_message), ) + .subcommand( + SubCommand::with_name("test") + .about("Tests that a book's Rust code samples compile") + .arg_from_usage(dir_message), + ) .subcommand( SubCommand::with_name("linkcheck") .about("Run linkcheck with mdBook 3") @@ -36,13 +41,12 @@ fn main() { match matches.subcommand() { ("build", Some(sub_matches)) => { if let Err(e) = build(sub_matches) { - eprintln!("Error: {}", e); - - for cause in e.iter().skip(1) { - eprintln!("\tCaused By: {}", cause); - } - - ::std::process::exit(101); + handle_error(e); + } + } + ("test", Some(sub_matches)) => { + if let Err(e) = test(sub_matches) { + handle_error(e); } } ("linkcheck", Some(sub_matches)) => { @@ -115,6 +119,8 @@ pub fn linkcheck( eprintln!("Timeout for link `{}`", link.link.uri); } else if err.is_server_error() { eprintln!("Server error for link `{}`", link.link.uri); + } else if !err.is_http() { + eprintln!("Non-HTTP-related error for link: {} {}", link.link.uri, err); } else { is_real_error = true; } @@ -146,6 +152,12 @@ pub fn build(args: &ArgMatches<'_>) -> Result3<()> { Ok(()) } +fn test(args: &ArgMatches<'_>) -> Result3<()> { + let book_dir = get_book_dir(args); + let mut book = MDBook::load(&book_dir)?; + book.test(vec![]) +} + fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf { if let Some(dir) = args.value_of("dir") { // Check if path is relative from current dir, or absolute... @@ -155,3 +167,13 @@ fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf { env::current_dir().unwrap() } } + +fn handle_error(error: mdbook::errors::Error) -> ! { + eprintln!("Error: {}", error); + + for cause in error.iter().skip(1) { + eprintln!("\tCaused By: {}", cause); + } + + ::std::process::exit(101); +} diff --git a/src/tools/rustdoc-js-std/tester.js b/src/tools/rustdoc-js-std/tester.js index d5f0ab9f429..08930ff1227 100644 --- a/src/tools/rustdoc-js-std/tester.js +++ b/src/tools/rustdoc-js-std/tester.js @@ -1,6 +1,5 @@ const fs = require('fs'); - -const TEST_FOLDER = 'src/test/rustdoc-js-std/'; +const path = require('path'); function getNextStep(content, pos, stop) { while (pos < content.length && content[pos] !== stop && @@ -246,17 +245,16 @@ function readFileMatching(dir, name, extension) { } function main(argv) { - if (argv.length !== 3) { - console.error("Expected toolchain to check as argument (for example \ - 'x86_64-apple-darwin')"); + if (argv.length !== 4) { + console.error("USAGE: node tester.js STD_DOCS TEST_FOLDER"); return 1; } - var toolchain = argv[2]; + var std_docs = argv[2]; + var test_folder = argv[3]; - var mainJs = readFileMatching("build/" + toolchain + "/doc/", "main", ".js"); - var ALIASES = readFileMatching("build/" + toolchain + "/doc/", "aliases", ".js"); - var searchIndex = readFileMatching("build/" + toolchain + "/doc/", - "search-index", ".js").split("\n"); + var mainJs = readFileMatching(std_docs, "main", ".js"); + var ALIASES = readFileMatching(std_docs, "aliases", ".js"); + var searchIndex = readFileMatching(std_docs, "search-index", ".js").split("\n"); if (searchIndex[searchIndex.length - 1].length === 0) { searchIndex.pop(); } @@ -265,7 +263,7 @@ function main(argv) { finalJS = ""; var arraysToLoad = ["itemTypes"]; - var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", + var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", "NO_TYPE_FILTER", "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA", "TY_PRIMITIVE", "TY_KEYWORD", "levenshtein_row2"]; @@ -287,8 +285,8 @@ function main(argv) { var errors = 0; - fs.readdirSync(TEST_FOLDER).forEach(function(file) { - var loadedFile = loadContent(readFile(TEST_FOLDER + file) + + fs.readdirSync(test_folder).forEach(function(file) { + var loadedFile = loadContent(readFile(path.join(test_folder, file)) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); const expected = loadedFile.EXPECTED; const query = loadedFile.QUERY; @@ -338,7 +336,7 @@ function main(argv) { console.log("OK"); } }); - return errors; + return errors > 0 ? 1 : 0; } process.exit(main(process.argv)); diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 833ce5d1370..143e1a7480d 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -1,8 +1,7 @@ const fs = require('fs'); +const path = require('path'); const { spawnSync } = require('child_process'); -const TEST_FOLDER = 'src/test/rustdoc-js/'; - function getNextStep(content, pos, stop) { while (pos < content.length && content[pos] !== stop && (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) { @@ -232,7 +231,7 @@ function load_files(out_folder, crate) { finalJS = ""; var arraysToLoad = ["itemTypes"]; - var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", + var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", "NO_TYPE_FILTER", "GENERICS_DATA", "NAME", "INPUTS_DATA", "OUTPUT_DATA", "TY_PRIMITIVE", "TY_KEYWORD", "levenshtein_row2"]; @@ -266,10 +265,11 @@ function main(argv) { var errors = 0; for (var j = 3; j < argv.length; ++j) { - const test_name = argv[j]; + const test_file = argv[j]; + const test_name = path.basename(test_file, ".js"); process.stdout.write('Checking "' + test_name + '" ... '); - if (!fs.existsSync(TEST_FOLDER + test_name + ".js")) { + if (!fs.existsSync(test_file)) { errors += 1; console.error("FAILED"); console.error("==> Missing '" + test_name + ".js' file..."); @@ -279,7 +279,7 @@ function main(argv) { const test_out_folder = out_folder + test_name; var [loaded, index] = load_files(test_out_folder, test_name); - var loadedFile = loadContent(readFile(TEST_FOLDER + test_name + ".js") + + var loadedFile = loadContent(readFile(test_file) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); const expected = loadedFile.EXPECTED; const query = loadedFile.QUERY; @@ -328,7 +328,7 @@ function main(argv) { console.log("OK"); } } - return errors; + return errors > 0 ? 1 : 0; } process.exit(main(process.argv)); diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 43cae31f33f..f984e5b61a5 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -5,8 +5,7 @@ authors = ["Alex Crichton "] edition = "2018" [dependencies] +cargo_metadata = "0.9.1" regex = "1" -serde = { version = "1.0.8", features = ["derive"] } -serde_json = "1.0.2" lazy_static = "1" walkdir = "2" diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 60d6ba090ec..792327c5213 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -1,13 +1,11 @@ -//! Checks the licenses of third-party dependencies by inspecting vendors. +//! Checks the licenses of third-party dependencies. -use std::collections::{BTreeSet, HashMap, HashSet}; -use std::fs; +use cargo_metadata::{Metadata, Package, PackageId, Resolve}; +use std::collections::{BTreeSet, HashSet}; use std::path::Path; -use std::process::Command; - -use serde::Deserialize; -use serde_json; +/// These are licenses that are allowed for all crates, including the runtime, +/// rustc, tools, etc. const LICENSES: &[&str] = &[ "MIT/Apache-2.0", "MIT / Apache-2.0", @@ -25,267 +23,274 @@ const LICENSES: &[&str] = &[ /// should be considered bugs. Exceptions are only allowed in Rust /// tooling. It is _crucial_ that no exception crates be dependencies /// of the Rust runtime (std/test). -const EXCEPTIONS: &[&str] = &[ - "mdbook", // MPL2, mdbook - "openssl", // BSD+advertising clause, cargo, mdbook - "pest", // MPL2, mdbook via handlebars - "arrayref", // BSD-2-Clause, mdbook via handlebars via pest - "thread-id", // Apache-2.0, mdbook - "toml-query", // MPL-2.0, mdbook - "is-match", // MPL-2.0, mdbook - "cssparser", // MPL-2.0, rustdoc - "smallvec", // MPL-2.0, rustdoc - "rdrand", // ISC, mdbook, rustfmt - "fuchsia-cprng", // BSD-3-Clause, mdbook, rustfmt - "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo - "fuchsia-zircon", // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir) - "cssparser-macros", // MPL-2.0, rustdoc - "selectors", // MPL-2.0, rustdoc - "clippy_lints", // MPL-2.0, rls - "colored", // MPL-2.0, rustfmt - "ordslice", // Apache-2.0, rls - "cloudabi", // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5) - "ryu", // Apache-2.0, rls/cargo/... (because of serde) - "bytesize", // Apache-2.0, cargo - "im-rc", // MPL-2.0+, cargo - "adler32", // BSD-3-Clause AND Zlib, cargo dep that isn't used - "constant_time_eq", // CC0-1.0, rustfmt - "utf8parse", // Apache-2.0 OR MIT, cargo via strip-ansi-escapes - "vte", // Apache-2.0 OR MIT, cargo via strip-ansi-escapes - "sized-chunks", // MPL-2.0+, cargo via im-rc - "bitmaps", // MPL-2.0+, cargo via im-rc +const EXCEPTIONS: &[(&str, &str)] = &[ + ("mdbook", "MPL-2.0"), // mdbook + ("openssl", "Apache-2.0"), // cargo, mdbook + ("arrayref", "BSD-2-Clause"), // mdbook via handlebars via pest + ("toml-query", "MPL-2.0"), // mdbook + ("toml-query_derive", "MPL-2.0"), // mdbook + ("is-match", "MPL-2.0"), // mdbook + ("rdrand", "ISC"), // mdbook, rustfmt + ("fuchsia-cprng", "BSD-3-Clause"), // mdbook, rustfmt + ("fuchsia-zircon-sys", "BSD-3-Clause"), // rustdoc, rustc, cargo + ("fuchsia-zircon", "BSD-3-Clause"), // rustdoc, rustc, cargo (jobserver & tempdir) + ("colored", "MPL-2.0"), // rustfmt + ("ordslice", "Apache-2.0"), // rls + ("cloudabi", "BSD-2-Clause"), // (rls -> crossbeam-channel 0.2 -> rand 0.5) + ("ryu", "Apache-2.0 OR BSL-1.0"), // rls/cargo/... (because of serde) + ("bytesize", "Apache-2.0"), // cargo + ("im-rc", "MPL-2.0+"), // cargo + ("adler32", "BSD-3-Clause AND Zlib"), // cargo dep that isn't used + ("constant_time_eq", "CC0-1.0"), // rustfmt + ("sized-chunks", "MPL-2.0+"), // cargo via im-rc + ("bitmaps", "MPL-2.0+"), // cargo via im-rc // FIXME: this dependency violates the documentation comment above: - "fortanix-sgx-abi", // MPL-2.0+, libstd but only for `sgx` target - "dunce", // CC0-1.0 mdbook-linkcheck - "codespan-reporting", // Apache-2.0 mdbook-linkcheck - "codespan", // Apache-2.0 mdbook-linkcheck - "crossbeam-channel", // MIT/Apache-2.0 AND BSD-2-Clause, cargo + ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target + ("dunce", "CC0-1.0"), // mdbook-linkcheck + ("codespan-reporting", "Apache-2.0"), // mdbook-linkcheck + ("codespan", "Apache-2.0"), // mdbook-linkcheck + ("crossbeam-channel", "MIT/Apache-2.0 AND BSD-2-Clause"), // cargo ]; +/// These are the root crates that are part of the runtime. The licenses for +/// these and all their dependencies *must not* be in the exception list. +const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"]; + /// Which crates to check against the whitelist? -const WHITELIST_CRATES: &[CrateVersion<'_>] = - &[CrateVersion("rustc", "0.0.0"), CrateVersion("rustc_codegen_llvm", "0.0.0")]; +const WHITELIST_CRATES: &[&str] = &["rustc", "rustc_codegen_llvm"]; /// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible. -const WHITELIST: &[Crate<'_>] = &[ - Crate("adler32"), - Crate("aho-corasick"), - Crate("annotate-snippets"), - Crate("ansi_term"), - Crate("arrayvec"), - Crate("atty"), - Crate("autocfg"), - Crate("backtrace"), - Crate("backtrace-sys"), - Crate("bitflags"), - Crate("build_const"), - Crate("byteorder"), - Crate("c2-chacha"), - Crate("cc"), - Crate("cfg-if"), - Crate("chalk-engine"), - Crate("chalk-macros"), - Crate("cloudabi"), - Crate("cmake"), - Crate("compiler_builtins"), - Crate("crc"), - Crate("crc32fast"), - Crate("crossbeam-deque"), - Crate("crossbeam-epoch"), - Crate("crossbeam-queue"), - Crate("crossbeam-utils"), - Crate("datafrog"), - Crate("dlmalloc"), - Crate("either"), - Crate("ena"), - Crate("env_logger"), - Crate("filetime"), - Crate("flate2"), - Crate("fortanix-sgx-abi"), - Crate("fuchsia-zircon"), - Crate("fuchsia-zircon-sys"), - Crate("getopts"), - Crate("getrandom"), - Crate("hashbrown"), - Crate("humantime"), - Crate("indexmap"), - Crate("itertools"), - Crate("jobserver"), - Crate("kernel32-sys"), - Crate("lazy_static"), - Crate("libc"), - Crate("libz-sys"), - Crate("lock_api"), - Crate("log"), - Crate("log_settings"), - Crate("measureme"), - Crate("memchr"), - Crate("memmap"), - Crate("memoffset"), - Crate("miniz-sys"), - Crate("miniz_oxide"), - Crate("miniz_oxide_c_api"), - Crate("nodrop"), - Crate("num_cpus"), - Crate("owning_ref"), - Crate("parking_lot"), - Crate("parking_lot_core"), - Crate("pkg-config"), - Crate("polonius-engine"), - Crate("ppv-lite86"), - Crate("proc-macro2"), - Crate("punycode"), - Crate("quick-error"), - Crate("quote"), - Crate("rand"), - Crate("rand_chacha"), - Crate("rand_core"), - Crate("rand_hc"), - Crate("rand_isaac"), - Crate("rand_pcg"), - Crate("rand_xorshift"), - Crate("redox_syscall"), - Crate("redox_termios"), - Crate("regex"), - Crate("regex-syntax"), - Crate("remove_dir_all"), - Crate("rustc-demangle"), - Crate("rustc-hash"), - Crate("rustc-rayon"), - Crate("rustc-rayon-core"), - Crate("rustc_version"), - Crate("scoped-tls"), - Crate("scopeguard"), - Crate("semver"), - Crate("semver-parser"), - Crate("serde"), - Crate("serde_derive"), - Crate("smallvec"), - Crate("stable_deref_trait"), - Crate("syn"), - Crate("synstructure"), - Crate("tempfile"), - Crate("termcolor"), - Crate("terminon"), - Crate("termion"), - Crate("termize"), - Crate("thread_local"), - Crate("ucd-util"), - Crate("unicode-normalization"), - Crate("unicode-script"), - Crate("unicode-security"), - Crate("unicode-width"), - Crate("unicode-xid"), - Crate("unreachable"), - Crate("utf8-ranges"), - Crate("vcpkg"), - Crate("version_check"), - Crate("void"), - Crate("wasi"), - Crate("winapi"), - Crate("winapi-build"), - Crate("winapi-i686-pc-windows-gnu"), - Crate("winapi-util"), - Crate("winapi-x86_64-pc-windows-gnu"), - Crate("wincolor"), - Crate("hermit-abi"), +/// +/// This list is here to provide a speed-bump to adding a new dependency to +/// rustc. Please check with the compiler team before adding an entry. +const WHITELIST: &[&str] = &[ + "adler32", + "aho-corasick", + "annotate-snippets", + "ansi_term", + "arrayvec", + "atty", + "autocfg", + "backtrace", + "backtrace-sys", + "bitflags", + "byteorder", + "c2-chacha", + "cc", + "cfg-if", + "cloudabi", + "cmake", + "compiler_builtins", + "crc32fast", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", + "datafrog", + "dlmalloc", + "either", + "ena", + "env_logger", + "filetime", + "flate2", + "fortanix-sgx-abi", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "getopts", + "getrandom", + "hashbrown", + "hermit-abi", + "humantime", + "indexmap", + "itertools", + "jobserver", + "kernel32-sys", + "lazy_static", + "libc", + "libz-sys", + "lock_api", + "log", + "log_settings", + "measureme", + "memchr", + "memmap", + "memoffset", + "miniz_oxide", + "nodrop", + "num_cpus", + "parking_lot", + "parking_lot_core", + "pkg-config", + "polonius-engine", + "ppv-lite86", + "proc-macro2", + "punycode", + "quick-error", + "quote", + "rand", + "rand_chacha", + "rand_core", + "rand_hc", + "rand_isaac", + "rand_pcg", + "rand_xorshift", + "redox_syscall", + "redox_termios", + "regex", + "regex-syntax", + "remove_dir_all", + "rustc-demangle", + "rustc-hash", + "rustc-rayon", + "rustc-rayon-core", + "rustc_version", + "scoped-tls", + "scopeguard", + "semver", + "semver-parser", + "serde", + "serde_derive", + "smallvec", + "stable_deref_trait", + "syn", + "synstructure", + "tempfile", + "termcolor", + "termion", + "termize", + "thread_local", + "ucd-util", + "unicode-normalization", + "unicode-script", + "unicode-security", + "unicode-width", + "unicode-xid", + "utf8-ranges", + "vcpkg", + "version_check", + "wasi", + "winapi", + "winapi-build", + "winapi-i686-pc-windows-gnu", + "winapi-util", + "winapi-x86_64-pc-windows-gnu", + "wincolor", // Yorick. - Crate("fallible-iterator"), - Crate("num-traits"), - Crate("rmp"), - Crate("rmp-serde"), - Crate("ykpack"), + "fallible-iterator", + "num-traits", + "rmp", + "rmp-serde", + "ykpack", ]; -// Some types for Serde to deserialize the output of `cargo metadata` to. - -#[derive(Deserialize)] -struct Output { - resolve: Resolve, -} - -#[derive(Deserialize)] -struct Resolve { - nodes: Vec, -} - -#[derive(Deserialize)] -struct ResolveNode { - id: String, - dependencies: Vec, -} - -/// A unique identifier for a crate. -#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)] -struct Crate<'a>(&'a str); // (name) - -#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)] -struct CrateVersion<'a>(&'a str, &'a str); // (name, version) - -impl Crate<'_> { - pub fn id_str(&self) -> String { - format!("{} ", self.0) - } -} - -impl<'a> CrateVersion<'a> { - /// Returns the struct and whether or not the dependency is in-tree. - pub fn from_str(s: &'a str) -> (Self, bool) { - let mut parts = s.split(' '); - let name = parts.next().unwrap(); - let version = parts.next().unwrap(); - let path = parts.next().unwrap(); - - let is_path_dep = path.starts_with("(path+"); - - (CrateVersion(name, version), is_path_dep) - } - - pub fn id_str(&self) -> String { - format!("{} {}", self.0, self.1) - } +/// Dependency checks. +/// +/// `path` is path to the `src` directory, `cargo` is path to the cargo executable. +pub fn check(path: &Path, cargo: &Path, bad: &mut bool) { + let mut cmd = cargo_metadata::MetadataCommand::new(); + cmd.cargo_path(cargo) + .manifest_path(path.parent().unwrap().join("Cargo.toml")) + .features(cargo_metadata::CargoOpt::AllFeatures); + let metadata = t!(cmd.exec()); + check_exceptions(&metadata, bad); + check_whitelist(&metadata, bad); + check_crate_duplicate(&metadata, bad); } -impl<'a> From> for Crate<'a> { - fn from(cv: CrateVersion<'a>) -> Crate<'a> { - Crate(cv.0) +/// Check that all licenses are in the valid list in `LICENSES`. +/// +/// Packages listed in `EXCEPTIONS` are allowed for tools. +fn check_exceptions(metadata: &Metadata, bad: &mut bool) { + // Validate the EXCEPTIONS list hasn't changed. + for (name, license) in EXCEPTIONS { + // Check that the package actually exists. + if !metadata.packages.iter().any(|p| p.name == *name) { + println!( + "could not find exception package `{}`\n\ + Remove from EXCEPTIONS list if it is no longer used.", + name + ); + *bad = true; + } + // Check that the license hasn't changed. + for pkg in metadata.packages.iter().filter(|p| p.name == *name) { + if pkg.name == "fuchsia-cprng" { + // This package doesn't declare a license expression. Manual + // inspection of the license file is necessary, which appears + // to be BSD-3-Clause. + assert!(pkg.license.is_none()); + continue; + } + match &pkg.license { + None => { + println!( + "dependency exception `{}` does not declare a license expression", + pkg.id + ); + *bad = true; + } + Some(pkg_license) => { + if pkg_license.as_str() != *license { + println!("dependency exception `{}` license has changed", name); + println!(" previously `{}` now `{}`", license, pkg_license); + println!(" update EXCEPTIONS for the new license"); + *bad = true; + } + } + } + } } -} -/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed. -/// -/// Specifically, this checks that the license is correct. -pub fn check(path: &Path, bad: &mut bool) { - // Check licences. - let path = path.join("../vendor"); - assert!(path.exists(), "vendor directory missing"); - let mut saw_dir = false; - for dir in t!(path.read_dir()) { - saw_dir = true; - let dir = t!(dir); + let exception_names: Vec<_> = EXCEPTIONS.iter().map(|(name, _license)| *name).collect(); + let runtime_ids = compute_runtime_crates(metadata); - // Skip our exceptions. - let is_exception = EXCEPTIONS.iter().any(|exception| { - dir.path().to_str().unwrap().contains(&format!("vendor/{}", exception)) - }); - if is_exception { + // Check if any package does not have a valid license. + for pkg in &metadata.packages { + if pkg.source.is_none() { + // No need to check local packages. continue; } - - let toml = dir.path().join("Cargo.toml"); - *bad = !check_license(&toml) || *bad; + if !runtime_ids.contains(&pkg.id) && exception_names.contains(&pkg.name.as_str()) { + continue; + } + let license = match &pkg.license { + Some(license) => license, + None => { + println!("dependency `{}` does not define a license expression", pkg.id,); + *bad = true; + continue; + } + }; + if !LICENSES.contains(&license.as_str()) { + if pkg.name == "fortanix-sgx-abi" { + // This is a specific exception because SGX is considered + // "third party". See + // https://github.com/rust-lang/rust/issues/62620 for more. In + // general, these should never be added. + continue; + } + println!("invalid license `{}` in `{}`", license, pkg.id); + *bad = true; + } } - assert!(saw_dir, "no vendored source"); } /// Checks the dependency of `WHITELIST_CRATES` at the given path. Changes `bad` to `true` if a /// check failed. /// /// Specifically, this checks that the dependencies are on the `WHITELIST`. -pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) { - // Get dependencies from Cargo metadata. - let resolve = get_deps(path, cargo); - +fn check_whitelist(metadata: &Metadata, bad: &mut bool) { + // Check that the WHITELIST does not have unused entries. + for name in WHITELIST { + if !metadata.packages.iter().any(|p| p.name == *name) { + println!( + "could not find whitelisted package `{}`\n\ + Remove from WHITELIST list if it is no longer used.", + name + ); + *bad = true; + } + } // Get the whitelist in a convenient form. let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect(); @@ -293,122 +298,59 @@ pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) { let mut visited = BTreeSet::new(); let mut unapproved = BTreeSet::new(); for &krate in WHITELIST_CRATES.iter() { - let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false); + let pkg = pkg_from_name(metadata, krate); + let mut bad = check_crate_whitelist(&whitelist, metadata, &mut visited, pkg); unapproved.append(&mut bad); } if !unapproved.is_empty() { println!("Dependencies not on the whitelist:"); for dep in unapproved { - println!("* {}", dep.id_str()); + println!("* {}", dep); } *bad = true; } - - check_crate_duplicate(&resolve, bad); -} - -fn check_license(path: &Path) -> bool { - if !path.exists() { - panic!("{} does not exist", path.display()); - } - let contents = t!(fs::read_to_string(&path)); - - let mut found_license = false; - for line in contents.lines() { - if !line.starts_with("license") { - continue; - } - let license = extract_license(line); - if !LICENSES.contains(&&*license) { - println!("invalid license {} in {}", license, path.display()); - return false; - } - found_license = true; - break; - } - if !found_license { - println!("no license in {}", path.display()); - return false; - } - - true -} - -fn extract_license(line: &str) -> String { - let first_quote = line.find('"'); - let last_quote = line.rfind('"'); - if let (Some(f), Some(l)) = (first_quote, last_quote) { - let license = &line[f + 1..l]; - license.into() - } else { - "bad-license-parse".into() - } -} - -/// Gets the dependencies of the crate at the given path using `cargo metadata`. -fn get_deps(path: &Path, cargo: &Path) -> Resolve { - // Run `cargo metadata` to get the set of dependencies. - let output = Command::new(cargo) - .arg("metadata") - .arg("--format-version") - .arg("1") - .arg("--manifest-path") - .arg(path.join("../Cargo.toml")) - .output() - .expect("Unable to run `cargo metadata`") - .stdout; - let output = String::from_utf8_lossy(&output); - let output: Output = serde_json::from_str(&output).unwrap(); - - output.resolve } /// Checks the dependencies of the given crate from the given cargo metadata to see if they are on /// the whitelist. Returns a list of illegal dependencies. fn check_crate_whitelist<'a>( - whitelist: &'a HashSet>, - resolve: &'a Resolve, - visited: &mut BTreeSet>, - krate: CrateVersion<'a>, - must_be_on_whitelist: bool, -) -> BTreeSet> { + whitelist: &'a HashSet<&'static str>, + metadata: &'a Metadata, + visited: &mut BTreeSet<&'a PackageId>, + krate: &'a Package, +) -> BTreeSet<&'a PackageId> { // This will contain bad deps. let mut unapproved = BTreeSet::new(); // Check if we have already visited this crate. - if visited.contains(&krate) { + if visited.contains(&krate.id) { return unapproved; } - visited.insert(krate); + visited.insert(&krate.id); // If this path is in-tree, we don't require it to be on the whitelist. - if must_be_on_whitelist { + if krate.source.is_some() { // If this dependency is not on `WHITELIST`, add to bad set. - if !whitelist.contains(&krate.into()) { - unapproved.insert(krate.into()); + if !whitelist.contains(krate.name.as_str()) { + unapproved.insert(&krate.id); } } - // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!). - let to_check = resolve - .nodes - .iter() - .find(|n| n.id.starts_with(&krate.id_str())) - .expect("crate does not exist"); + // Do a DFS in the crate graph. + let to_check = deps_of(metadata, &krate.id); - for dep in to_check.dependencies.iter() { - let (krate, is_path_dep) = CrateVersion::from_str(dep); - - let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep); + for dep in to_check { + let mut bad = check_crate_whitelist(whitelist, metadata, visited, dep); unapproved.append(&mut bad); } unapproved } -fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) { +/// Prevents multiple versions of some expensive crates. +fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) { const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[ // These two crates take quite a long time to build, so don't allow two versions of them // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times @@ -416,19 +358,97 @@ fn check_crate_duplicate(resolve: &Resolve, bad: &mut bool) { "cargo", "rustc-ap-syntax", ]; - let mut name_to_id: HashMap<_, Vec<_>> = HashMap::new(); - for node in resolve.nodes.iter() { - name_to_id.entry(node.id.split_whitespace().next().unwrap()).or_default().push(&node.id); - } - for name in FORBIDDEN_TO_HAVE_DUPLICATES { - if name_to_id[name].len() <= 1 { - continue; - } - println!("crate `{}` is duplicated in `Cargo.lock`", name); - for id in name_to_id[name].iter() { - println!(" * {}", id); + for &name in FORBIDDEN_TO_HAVE_DUPLICATES { + let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect(); + match matches.len() { + 0 => { + println!( + "crate `{}` is missing, update `check_crate_duplicate` \ + if it is no longer used", + name + ); + *bad = true; + } + 1 => {} + _ => { + println!( + "crate `{}` is duplicated in `Cargo.lock`, \ + it is too expensive to build multiple times, \ + so make sure only one version appears across all dependencies", + name + ); + for pkg in matches { + println!(" * {}", pkg.id); + } + *bad = true; + } } - *bad = true; + } +} + +/// Returns a list of dependencies for the given package. +fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> { + let resolve = metadata.resolve.as_ref().unwrap(); + let node = resolve + .nodes + .iter() + .find(|n| &n.id == pkg_id) + .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id)); + node.deps + .iter() + .map(|dep| { + metadata.packages.iter().find(|pkg| pkg.id == dep.pkg).unwrap_or_else(|| { + panic!("could not find dep `{}` for pkg `{}` in resolve", dep.pkg, pkg_id) + }) + }) + .collect() +} + +/// Finds a package with the given name. +fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package { + let mut i = metadata.packages.iter().filter(|p| p.name == name); + let result = + i.next().unwrap_or_else(|| panic!("could not find package `{}` in package list", name)); + assert!(i.next().is_none(), "more than one package found for `{}`", name); + result +} + +/// Finds all the packages that are in the rust runtime. +fn compute_runtime_crates<'a>(metadata: &'a Metadata) -> HashSet<&'a PackageId> { + let resolve = metadata.resolve.as_ref().unwrap(); + let mut result = HashSet::new(); + for name in RUNTIME_CRATES { + let id = &pkg_from_name(metadata, name).id; + normal_deps_of_r(resolve, id, &mut result); + } + result +} + +/// Recursively find all normal dependencies. +fn normal_deps_of_r<'a>( + resolve: &'a Resolve, + pkg_id: &'a PackageId, + result: &mut HashSet<&'a PackageId>, +) { + if !result.insert(pkg_id) { + return; + } + let node = resolve + .nodes + .iter() + .find(|n| &n.id == pkg_id) + .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id)); + // Don't care about dev-dependencies. + // Build dependencies *shouldn't* matter unless they do some kind of + // codegen. For now we'll assume they don't. + let deps = node.deps.iter().filter(|node_dep| { + node_dep + .dep_kinds + .iter() + .any(|kind_info| kind_info.kind == cargo_metadata::DependencyKind::Normal) + }); + for dep in deps { + normal_deps_of_r(resolve, &dep.pkg, result); } } diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 12f93a87cb1..d9320e9147c 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -63,20 +63,6 @@ pub struct CollectedFeatures { pub fn collect_lib_features(base_src_path: &Path) -> Features { let mut lib_features = Features::new(); - // This library feature is defined in the `compiler_builtins` crate, which - // has been moved out-of-tree. Now it can no longer be auto-discovered by - // `tidy`, because we need to filter out its (submodule) directory. Manually - // add it to the set of known library features so we can still generate docs. - lib_features.insert( - "compiler_builtins_lib".to_owned(), - Feature { - level: Status::Unstable, - since: None, - has_gate_test: false, - tracking_issue: None, - }, - ); - map_lib_features(base_src_path, &mut |res, _, _| { if let Ok((name, feature)) = res { lib_features.insert(name.to_owned(), feature); diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index c8c61b6fb50..be1e598d8d4 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -58,6 +58,7 @@ fn filter_dirs(path: &Path) -> bool { "src/tools/rls", "src/tools/rust-installer", "src/tools/rustfmt", + "src/doc/book", // Filter RLS output directories "target/rls", ]; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index ec8b14c288a..e2856c69055 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -1,8 +1,8 @@ //! Tidy checks source code in this repository. //! //! This program runs all of the various tidy checks for style, cleanliness, -//! etc. This is run by default on `make check` and as part of the auto -//! builders. +//! etc. This is run by default on `./x.py test` and as part of the auto +//! builders. The tidy checks can be executed with `./x.py test tidy`. #![deny(warnings)] @@ -30,10 +30,7 @@ fn main() { pal::check(&path, &mut bad); unstable_book::check(&path, collected, &mut bad); unit_tests::check(&path, &mut bad); - if !args.iter().any(|s| *s == "--no-vendor") { - deps::check(&path, &mut bad); - } - deps::check_whitelist(&path, &cargo, &mut bad); + deps::check(&path, &cargo, &mut bad); extdeps::check(&path, &mut bad); ui_tests::check(&path, &mut bad); error_codes_check::check(&path, &mut bad); diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index dcd4c9e8ef7..247e85603cf 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -41,7 +41,7 @@ const EXCEPTION_PATHS: &[&str] = &[ "src/libpanic_unwind", "src/libunwind", // black_box implementation is LLVM-version specific and it uses - // target_os to tell targets with different LLVM-versions appart + // target_os to tell targets with different LLVM-versions apart // (e.g. `wasm32-unknown-emscripten` vs `wasm32-unknown-unknown`): "src/libcore/hint.rs", "src/libstd/sys/", // Platform-specific code for std lives here. @@ -59,6 +59,8 @@ const EXCEPTION_PATHS: &[&str] = &[ "src/libstd/sys_common/mod.rs", "src/libstd/sys_common/net.rs", "src/libstd/sys_common/backtrace.rs", + // panic_unwind shims + "src/libstd/panicking.rs", "src/libterm", // Not sure how to make this crate portable, but test crate needs it. "src/libtest", // Probably should defer to unstable `std::sys` APIs. "src/libstd/sync/mpsc", // some tests are only run on non-emscripten @@ -76,7 +78,7 @@ const EXCEPTION_PATHS: &[&str] = &[ "src/tools", "src/librustc", "src/librustdoc", - "src/libsyntax", + "src/librustc_ast", "src/bootstrap", ]; diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs index 472d66459d7..7dfb6224d24 100644 --- a/src/tools/tidy/src/unstable_book.rs +++ b/src/tools/tidy/src/unstable_book.rs @@ -1,4 +1,4 @@ -use crate::features::{CollectedFeatures, Feature, Features, Status}; +use crate::features::{CollectedFeatures, Features, Status}; use std::collections::BTreeSet; use std::fs; use std::path::{Path, PathBuf}; @@ -73,26 +73,12 @@ fn collect_unstable_book_lib_features_section_file_names(base_src_path: &Path) - pub fn check(path: &Path, features: CollectedFeatures, bad: &mut bool) { let lang_features = features.lang; - let mut lib_features = features + let lib_features = features .lib .into_iter() .filter(|&(ref name, _)| !lang_features.contains_key(name)) .collect::(); - // This library feature is defined in the `compiler_builtins` crate, which - // has been moved out-of-tree. Now it can no longer be auto-discovered by - // `tidy`, because we need to filter out its (submodule) directory. Manually - // add it to the set of known library features so we can still generate docs. - lib_features.insert( - "compiler_builtins_lib".to_owned(), - Feature { - level: Status::Unstable, - since: None, - has_gate_test: false, - tracking_issue: None, - }, - ); - // Library features let unstable_lib_feature_names = collect_unstable_feature_names(&lib_features); let unstable_book_lib_features_section_file_names = diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs index be8508e3973..839d914baa9 100644 --- a/src/tools/unicode-table-generator/src/main.rs +++ b/src/tools/unicode-table-generator/src/main.rs @@ -147,7 +147,7 @@ fn main() { eprintln!("Must provide path to write unicode tables to"); eprintln!( "e.g. {} src/libcore/unicode/unicode_data.rs", - std::env::args().nth(0).unwrap_or_default() + std::env::args().next().unwrap_or_default() ); std::process::exit(1); }); diff --git a/triagebot.toml b/triagebot.toml index 7ece7f977ce..ec327715833 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,6 +1,7 @@ [relabel] allow-unauthenticated = [ "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*", + "D-*", "requires-nightly", # I-* without I-nominated "I-*", "!I-nominated", @@ -10,23 +11,25 @@ allow-unauthenticated = [ [assign] [ping.icebreakers-llvm] +alias = ["llvm", "llvms"] message = """\ Hey LLVM ICE-breakers! This bug has been identified as a good "LLVM ICE-breaking candidate". In case it's useful, here are some [instructions] for tackling these sorts of bugs. Maybe take a look? Thanks! <3 -[instructions]: https://rust-lang.github.io/rustc-guide/ice-breaker/llvm.html +[instructions]: https://rustc-dev-guide.rust-lang.org/ice-breaker/llvm.html """ label = "ICEBreaker-LLVM" [ping.icebreakers-cleanup-crew] +alias = ["cleanup", "cleanups", "shrink", "reduce", "bisect"] message = """\ Hey Cleanup Crew ICE-breakers! This bug has been identified as a good "Cleanup ICE-breaking candidate". In case it's useful, here are some [instructions] for tackling these sorts of bugs. Maybe take a look? Thanks! <3 -[instructions]: https://rust-lang.github.io/rustc-guide/ice-breaker/cleanup-crew.html +[instructions]: https://rustc-dev-guide.rust-lang.org/ice-breaker/cleanup-crew.html """ label = "ICEBreaker-Cleanup-Crew"

(&self, value: P) -> Obligation<'tcx, P> { + Obligation { + cause: self.cause.clone(), + param_env: self.param_env, + recursion_depth: self.recursion_depth, + predicate: value, + } + } +} + +impl<'tcx> FulfillmentError<'tcx> { + pub fn new( + obligation: PredicateObligation<'tcx>, + code: FulfillmentErrorCode<'tcx>, + ) -> FulfillmentError<'tcx> { + FulfillmentError { obligation, code, points_at_arg_span: false } + } +} + +impl<'tcx> TraitObligation<'tcx> { + pub fn self_ty(&self) -> ty::Binder> { + self.predicate.map_bound(|p| p.self_ty()) + } +} diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs new file mode 100644 index 00000000000..183e4be1890 --- /dev/null +++ b/src/librustc_infer/traits/project.rs @@ -0,0 +1,191 @@ +//! Code for projecting associated types out of trait references. + +use super::PredicateObligation; + +use rustc::ty::fold::TypeFoldable; +use rustc::ty::{self, Ty}; +use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; + +pub use rustc::traits::Reveal; + +#[derive(Clone)] +pub struct MismatchedProjectionTypes<'tcx> { + pub err: ty::error::TypeError<'tcx>, +} + +#[derive(Clone, TypeFoldable)] +pub struct Normalized<'tcx, T> { + pub value: T, + pub obligations: Vec>, +} + +pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>; + +impl<'tcx, T> Normalized<'tcx, T> { + pub fn with(self, value: U) -> Normalized<'tcx, U> { + Normalized { value: value, obligations: self.obligations } + } +} + +// # Cache + +/// The projection cache. Unlike the standard caches, this can include +/// infcx-dependent type variables, therefore we have to roll the +/// cache back each time we roll a snapshot back, to avoid assumptions +/// on yet-unresolved inference variables. Types with placeholder +/// regions also have to be removed when the respective snapshot ends. +/// +/// Because of that, projection cache entries can be "stranded" and left +/// inaccessible when type variables inside the key are resolved. We make no +/// attempt to recover or remove "stranded" entries, but rather let them be +/// (for the lifetime of the infcx). +/// +/// Entries in the projection cache might contain inference variables +/// that will be resolved by obligations on the projection cache entry (e.g., +/// when a type parameter in the associated type is constrained through +/// an "RFC 447" projection on the impl). +/// +/// When working with a fulfillment context, the derived obligations of each +/// projection cache entry will be registered on the fulfillcx, so any users +/// that can wait for a fulfillcx fixed point need not care about this. However, +/// users that don't wait for a fixed point (e.g., trait evaluation) have to +/// resolve the obligations themselves to make sure the projected result is +/// ok and avoid issues like #43132. +/// +/// If that is done, after evaluation the obligations, it is a good idea to +/// call `ProjectionCache::complete` to make sure the obligations won't be +/// re-evaluated and avoid an exponential worst-case. +// +// FIXME: we probably also want some sort of cross-infcx cache here to +// reduce the amount of duplication. Let's see what we get with the Chalk reforms. +#[derive(Default)] +pub struct ProjectionCache<'tcx> { + map: SnapshotMap, ProjectionCacheEntry<'tcx>>, +} + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct ProjectionCacheKey<'tcx> { + ty: ty::ProjectionTy<'tcx>, +} + +impl ProjectionCacheKey<'tcx> { + pub fn new(ty: ty::ProjectionTy<'tcx>) -> Self { + Self { ty } + } +} + +#[derive(Clone, Debug)] +pub enum ProjectionCacheEntry<'tcx> { + InProgress, + Ambiguous, + Error, + NormalizedTy(NormalizedTy<'tcx>), +} + +// N.B., intentionally not Clone +pub struct ProjectionCacheSnapshot { + snapshot: Snapshot, +} + +impl<'tcx> ProjectionCache<'tcx> { + pub fn clear(&mut self) { + self.map.clear(); + } + + pub fn snapshot(&mut self) -> ProjectionCacheSnapshot { + ProjectionCacheSnapshot { snapshot: self.map.snapshot() } + } + + pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) { + self.map.rollback_to(snapshot.snapshot); + } + + pub fn rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) { + self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders()); + } + + pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) { + self.map.commit(snapshot.snapshot); + } + + /// Try to start normalize `key`; returns an error if + /// normalization already occurred (this error corresponds to a + /// cache hit, so it's actually a good thing). + pub fn try_start( + &mut self, + key: ProjectionCacheKey<'tcx>, + ) -> Result<(), ProjectionCacheEntry<'tcx>> { + if let Some(entry) = self.map.get(&key) { + return Err(entry.clone()); + } + + self.map.insert(key, ProjectionCacheEntry::InProgress); + Ok(()) + } + + /// Indicates that `key` was normalized to `value`. + pub fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) { + debug!( + "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", + key, value + ); + let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value)); + assert!(!fresh_key, "never started projecting `{:?}`", key); + } + + /// Mark the relevant projection cache key as having its derived obligations + /// complete, so they won't have to be re-computed (this is OK to do in a + /// snapshot - if the snapshot is rolled back, the obligations will be + /// marked as incomplete again). + pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) { + let ty = match self.map.get(&key) { + Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => { + debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); + ty.value + } + ref value => { + // Type inference could "strand behind" old cache entries. Leave + // them alone for now. + debug!("ProjectionCacheEntry::complete({:?}) - ignoring {:?}", key, value); + return; + } + }; + + self.map.insert( + key, + ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }), + ); + } + + /// A specialized version of `complete` for when the key's value is known + /// to be a NormalizedTy. + pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) { + // We want to insert `ty` with no obligations. If the existing value + // already has no obligations (as is common) we don't insert anything. + if !ty.obligations.is_empty() { + self.map.insert( + key, + ProjectionCacheEntry::NormalizedTy(Normalized { + value: ty.value, + obligations: vec![], + }), + ); + } + } + + /// Indicates that trying to normalize `key` resulted in + /// ambiguity. No point in trying it again then until we gain more + /// type information (in which case, the "fully resolved" key will + /// be different). + pub fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) { + let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous); + assert!(!fresh, "never started projecting `{:?}`", key); + } + + /// Indicates that trying to normalize `key` resulted in + /// error. + pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) { + let fresh = self.map.insert(key, ProjectionCacheEntry::Error); + assert!(!fresh, "never started projecting `{:?}`", key); + } +} diff --git a/src/librustc_infer/traits/structural_impls.rs b/src/librustc_infer/traits/structural_impls.rs new file mode 100644 index 00000000000..6630f664f96 --- /dev/null +++ b/src/librustc_infer/traits/structural_impls.rs @@ -0,0 +1,71 @@ +use crate::traits; +use crate::traits::project::Normalized; +use rustc::ty; +use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; + +use std::fmt; + +// Structural impls for the structs in `traits`. + +impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Normalized({:?}, {:?})", self.value, self.obligations) + } +} + +impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if ty::tls::with(|tcx| tcx.sess.verbose()) { + write!( + f, + "Obligation(predicate={:?}, cause={:?}, param_env={:?}, depth={})", + self.predicate, self.cause, self.param_env, self.recursion_depth + ) + } else { + write!(f, "Obligation(predicate={:?}, depth={})", self.predicate, self.recursion_depth) + } + } +} + +impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code) + } +} + +impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + super::CodeSelectionError(ref e) => write!(f, "{:?}", e), + super::CodeProjectionError(ref e) => write!(f, "{:?}", e), + super::CodeSubtypeError(ref a, ref b) => { + write!(f, "CodeSubtypeError({:?}, {:?})", a, b) + } + super::CodeAmbiguity => write!(f, "Ambiguity"), + } + } +} + +impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "MismatchedProjectionTypes({:?})", self.err) + } +} + +/////////////////////////////////////////////////////////////////////////// +// TypeFoldable implementations. + +impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + traits::Obligation { + cause: self.cause.clone(), + recursion_depth: self.recursion_depth, + predicate: self.predicate.fold_with(folder), + param_env: self.param_env.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.predicate.visit_with(visitor) + } +} diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs new file mode 100644 index 00000000000..a7c02671115 --- /dev/null +++ b/src/librustc_infer/traits/util.rs @@ -0,0 +1,225 @@ +use smallvec::smallvec; + +use rustc::ty::outlives::Component; +use rustc::ty::{self, ToPolyTraitRef, TyCtxt}; +use rustc_data_structures::fx::FxHashSet; + +fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + match *pred { + ty::Predicate::Trait(ref data, constness) => { + ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness) + } + + ty::Predicate::RegionOutlives(ref data) => { + ty::Predicate::RegionOutlives(tcx.anonymize_late_bound_regions(data)) + } + + ty::Predicate::TypeOutlives(ref data) => { + ty::Predicate::TypeOutlives(tcx.anonymize_late_bound_regions(data)) + } + + ty::Predicate::Projection(ref data) => { + ty::Predicate::Projection(tcx.anonymize_late_bound_regions(data)) + } + + ty::Predicate::WellFormed(data) => ty::Predicate::WellFormed(data), + + ty::Predicate::ObjectSafe(data) => ty::Predicate::ObjectSafe(data), + + ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { + ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) + } + + ty::Predicate::Subtype(ref data) => { + ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)) + } + + ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::Predicate::ConstEvaluatable(def_id, substs) + } + } +} + +struct PredicateSet<'tcx> { + tcx: TyCtxt<'tcx>, + set: FxHashSet>, +} + +impl PredicateSet<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Self { + Self { tcx: tcx, set: Default::default() } + } + + fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool { + // We have to be careful here because we want + // + // for<'a> Foo<&'a int> + // + // and + // + // for<'b> Foo<&'b int> + // + // to be considered equivalent. So normalize all late-bound + // regions before we throw things into the underlying set. + self.set.insert(anonymize_predicate(self.tcx, pred)) + } +} + +impl>> Extend for PredicateSet<'tcx> { + fn extend>(&mut self, iter: I) { + for pred in iter { + self.insert(pred.as_ref()); + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// `Elaboration` iterator +/////////////////////////////////////////////////////////////////////////// + +/// "Elaboration" is the process of identifying all the predicates that +/// are implied by a source predicate. Currently, this basically means +/// walking the "supertraits" and other similar assumptions. For example, +/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd` +/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that +/// `T: Foo`, then we know that `T: 'static`. +pub struct Elaborator<'tcx> { + stack: Vec>, + visited: PredicateSet<'tcx>, +} + +pub fn elaborate_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + mut predicates: Vec>, +) -> Elaborator<'tcx> { + let mut visited = PredicateSet::new(tcx); + predicates.retain(|pred| visited.insert(pred)); + Elaborator { stack: predicates, visited } +} + +impl Elaborator<'tcx> { + fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) { + let tcx = self.visited.tcx; + match *predicate { + ty::Predicate::Trait(ref data, _) => { + // Get predicates declared on the trait. + let predicates = tcx.super_predicates_of(data.def_id()); + + let predicates = predicates + .predicates + .iter() + .map(|(pred, _)| pred.subst_supertrait(tcx, &data.to_poly_trait_ref())); + debug!("super_predicates: data={:?} predicates={:?}", data, predicates.clone()); + + // Only keep those bounds that we haven't already seen. + // This is necessary to prevent infinite recursion in some + // cases. One common case is when people define + // `trait Sized: Sized { }` rather than `trait Sized { }`. + let visited = &mut self.visited; + let predicates = predicates.filter(|pred| visited.insert(pred)); + + self.stack.extend(predicates); + } + ty::Predicate::WellFormed(..) => { + // Currently, we do not elaborate WF predicates, + // although we easily could. + } + ty::Predicate::ObjectSafe(..) => { + // Currently, we do not elaborate object-safe + // predicates. + } + ty::Predicate::Subtype(..) => { + // Currently, we do not "elaborate" predicates like `X <: Y`, + // though conceivably we might. + } + ty::Predicate::Projection(..) => { + // Nothing to elaborate in a projection predicate. + } + ty::Predicate::ClosureKind(..) => { + // Nothing to elaborate when waiting for a closure's kind to be inferred. + } + ty::Predicate::ConstEvaluatable(..) => { + // Currently, we do not elaborate const-evaluatable + // predicates. + } + ty::Predicate::RegionOutlives(..) => { + // Nothing to elaborate from `'a: 'b`. + } + ty::Predicate::TypeOutlives(ref data) => { + // We know that `T: 'a` for some type `T`. We can + // often elaborate this. For example, if we know that + // `[U]: 'a`, that implies that `U: 'a`. Similarly, if + // we know `&'a U: 'b`, then we know that `'a: 'b` and + // `U: 'b`. + // + // We can basically ignore bound regions here. So for + // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to + // `'a: 'b`. + + // Ignore `for<'a> T: 'a` -- we might in the future + // consider this as evidence that `T: 'static`, but + // I'm a bit wary of such constructions and so for now + // I want to be conservative. --nmatsakis + let ty_max = data.skip_binder().0; + let r_min = data.skip_binder().1; + if r_min.is_late_bound() { + return; + } + + let visited = &mut self.visited; + let mut components = smallvec![]; + tcx.push_outlives_components(ty_max, &mut components); + self.stack.extend( + components + .into_iter() + .filter_map(|component| match component { + Component::Region(r) => { + if r.is_late_bound() { + None + } else { + Some(ty::Predicate::RegionOutlives(ty::Binder::dummy( + ty::OutlivesPredicate(r, r_min), + ))) + } + } + + Component::Param(p) => { + let ty = tcx.mk_ty_param(p.index, p.name); + Some(ty::Predicate::TypeOutlives(ty::Binder::dummy( + ty::OutlivesPredicate(ty, r_min), + ))) + } + + Component::UnresolvedInferenceVariable(_) => None, + + Component::Projection(_) | Component::EscapingProjection(_) => { + // We can probably do more here. This + // corresponds to a case like `>::U: 'b`. + None + } + }) + .filter(|p| visited.insert(p)), + ); + } + } + } +} + +impl Iterator for Elaborator<'tcx> { + type Item = ty::Predicate<'tcx>; + + fn size_hint(&self) -> (usize, Option) { + (self.stack.len(), None) + } + + fn next(&mut self) -> Option> { + // Extract next item from top-most stack frame, if any. + if let Some(pred) = self.stack.pop() { + self.elaborate(&pred); + Some(pred) + } else { + None + } + } +} diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index de7a9f4f5af..e84181f1d75 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -13,7 +13,7 @@ doctest = false log = "0.4" rayon = { version = "0.3.0", package = "rustc-rayon" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } rustc_attr = { path = "../librustc_attr" } rustc_builtin_macros = { path = "../librustc_builtin_macros" } rustc_expand = { path = "../librustc_expand" } @@ -31,6 +31,7 @@ rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_codegen_llvm = { path = "../librustc_codegen_llvm", optional = true } rustc_hir = { path = "../librustc_hir" } +rustc_infer = { path = "../librustc_infer" } rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } rustc_mir_build = { path = "../librustc_mir_build" } @@ -41,6 +42,7 @@ rustc_errors = { path = "../librustc_errors" } rustc_plugin_impl = { path = "../librustc_plugin_impl" } rustc_privacy = { path = "../librustc_privacy" } rustc_resolve = { path = "../librustc_resolve" } +rustc_trait_selection = { path = "../librustc_trait_selection" } rustc_ty = { path = "../librustc_ty" } tempfile = "3.0.5" once_cell = "1" diff --git a/src/librustc_interface/callbacks.rs b/src/librustc_interface/callbacks.rs index 803e8958572..0345b82d3bb 100644 --- a/src/librustc_interface/callbacks.rs +++ b/src/librustc_interface/callbacks.rs @@ -13,7 +13,7 @@ use rustc::ty::tls; use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS}; use std::fmt; -/// This is a callback from libsyntax as it cannot access the implicit state +/// This is a callback from librustc_ast as it cannot access the implicit state /// in librustc otherwise. fn span_debug(span: rustc_span::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result { tls::with_opt(|tcx| { @@ -25,7 +25,7 @@ fn span_debug(span: rustc_span::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result }) } -/// This is a callback from libsyntax as it cannot access the implicit state +/// This is a callback from librustc_ast as it cannot access the implicit state /// in librustc otherwise. It is used to when diagnostic messages are /// emitted and stores them in the current query, if there is one. fn track_diagnostic(diagnostic: &Diagnostic) { @@ -58,4 +58,5 @@ pub fn setup_callbacks() { rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_))); + rustc::ty::RESOLVE_INSTANCE.swap(&(rustc_ty::instance::resolve_instance as _)); } diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index e213a4d33a6..c5ebcf0696f 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -1,12 +1,10 @@ pub use crate::passes::BoxedResolver; use crate::util; -use rustc::lint; -use rustc::session::config::{self, ErrorOutputType, Input, OutputFilenames}; -use rustc::session::early_error; -use rustc::session::{DiagnosticOutput, Session}; use rustc::ty; use rustc::util::common::ErrorReported; +use rustc_ast::ast::{self, MetaItemKind}; +use rustc_ast::token; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; @@ -14,14 +12,16 @@ use rustc_data_structures::OnDrop; use rustc_errors::registry::Registry; use rustc_lint::LintStore; use rustc_parse::new_parser_from_source_str; +use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames}; +use rustc_session::early_error; +use rustc_session::lint; use rustc_session::parse::{CrateConfig, ParseSess}; +use rustc_session::{DiagnosticOutput, Session}; use rustc_span::edition; use rustc_span::source_map::{FileLoader, FileName, SourceMap}; use std::path::PathBuf; use std::result; use std::sync::{Arc, Mutex}; -use syntax::ast::{self, MetaItemKind}; -use syntax::token; pub type Result = result::Result; @@ -78,7 +78,7 @@ impl Compiler { /// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option)> { - syntax::with_default_globals(move || { + rustc_ast::with_default_globals(move || { let cfg = cfgspecs .into_iter() .map(|s| { diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 526fb6a9e2c..fde80c06d95 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -5,19 +5,15 @@ use crate::util; use log::{info, log_enabled, warn}; use rustc::arena::Arena; use rustc::dep_graph::DepGraph; -use rustc::hir::map; -use rustc::lint; +use rustc::hir::map::Definitions; use rustc::middle; use rustc::middle::cstore::{CrateStore, MetadataLoader, MetadataLoaderDyn}; -use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType}; -use rustc::session::config::{PpMode, PpSourceMode}; -use rustc::session::search_paths::PathKind; -use rustc::session::Session; use rustc::sir::Sir; -use rustc::traits; use rustc::ty::steal::Steal; use rustc::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc::util::common::ErrorReported; +use rustc_ast::mut_visit::MutVisitor; +use rustc_ast::{self, ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_codegen_utils::link::filename_for_metadata; @@ -34,11 +30,15 @@ use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; use rustc_resolve::{Resolver, ResolverArenas}; +use rustc_session::config::{self, CrateType, Input, OutputFilenames, OutputType}; +use rustc_session::config::{PpMode, PpSourceMode}; +use rustc_session::lint; +use rustc_session::search_paths::PathKind; +use rustc_session::Session; use rustc_span::symbol::Symbol; use rustc_span::FileName; +use rustc_trait_selection::traits; use rustc_typeck as typeck; -use syntax::mut_visit::MutVisitor; -use syntax::{self, ast, visit}; use rustc_serialize::json; use tempfile::Builder as TempFileBuilder; @@ -190,7 +190,7 @@ pub fn register_plugins<'a>( } sess.time("recursion_limit", || { - middle::recursion_limit::update_limits(sess, &krate); + middle::limits::update_limits(sess, &krate); }); let mut lint_store = rustc_lint::new_lint_store( @@ -211,14 +211,7 @@ pub fn register_plugins<'a>( Ok((krate, Lrc::new(lint_store))) } -fn configure_and_expand_inner<'a>( - sess: &'a Session, - lint_store: &'a LintStore, - mut krate: ast::Crate, - crate_name: &str, - resolver_arenas: &'a ResolverArenas<'a>, - metadata_loader: &'a MetadataLoaderDyn, -) -> Result<(ast::Crate, Resolver<'a>)> { +fn pre_expansion_lint(sess: &Session, lint_store: &LintStore, krate: &ast::Crate) { sess.time("pre_AST_expansion_lint_checks", || { rustc_lint::check_ast_crate( sess, @@ -229,6 +222,17 @@ fn configure_and_expand_inner<'a>( rustc_lint::BuiltinCombinedPreExpansionLintPass::new(), ); }); +} + +fn configure_and_expand_inner<'a>( + sess: &'a Session, + lint_store: &'a LintStore, + mut krate: ast::Crate, + crate_name: &str, + resolver_arenas: &'a ResolverArenas<'a>, + metadata_loader: &'a MetadataLoaderDyn, +) -> Result<(ast::Crate, Resolver<'a>)> { + pre_expansion_lint(sess, lint_store, &krate); let mut resolver = Resolver::new(sess, &krate, crate_name, metadata_loader, &resolver_arenas); rustc_builtin_macros::register_builtin_macros(&mut resolver, sess.edition()); @@ -292,7 +296,8 @@ fn configure_and_expand_inner<'a>( ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) }; - let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver); + let extern_mod_loaded = |k: &ast::Crate| pre_expansion_lint(sess, lint_store, k); + let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver, Some(&extern_mod_loaded)); // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); @@ -697,8 +702,8 @@ impl<'tcx> QueryContext<'tcx> { ty::tls::enter_global(self.0, |tcx| f(tcx)) } - pub fn print_stats(&self) { - self.0.queries.print_stats() + pub fn print_stats(&mut self) { + self.enter(|tcx| ty::query::print_stats(tcx)) } } @@ -714,10 +719,7 @@ pub fn create_global_ctxt<'tcx>( arena: &'tcx WorkerLocal>, ) -> QueryContext<'tcx> { let sess = &compiler.session(); - let defs = mem::take(&mut resolver_outputs.definitions); - - // Construct the HIR map. - let hir_map = map::map_crate(sess, &*resolver_outputs.cstore, krate, dep_graph, defs); + let defs: &'tcx Definitions = arena.alloc(mem::take(&mut resolver_outputs.definitions)); let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess); @@ -743,7 +745,9 @@ pub fn create_global_ctxt<'tcx>( extern_providers, arena, resolver_outputs, - hir_map, + krate, + defs, + dep_graph, query_result_on_disk_cache, &crate_name, &outputs, @@ -764,6 +768,8 @@ pub fn create_global_ctxt<'tcx>( fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> { assert_eq!(cnum, LOCAL_CRATE); + rustc::hir::map::check_crate(tcx); + let sess = tcx.sess; let mut entry_point = None; diff --git a/src/librustc_interface/proc_macro_decls.rs b/src/librustc_interface/proc_macro_decls.rs index 9238f88b2b5..076a8cef92c 100644 --- a/src/librustc_interface/proc_macro_decls.rs +++ b/src/librustc_interface/proc_macro_decls.rs @@ -1,10 +1,10 @@ use rustc::ty::query::Providers; use rustc::ty::TyCtxt; +use rustc_ast::attr; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_span::symbol::sym; -use syntax::attr; pub fn find(tcx: TyCtxt<'_>) -> Option { tcx.proc_macro_decls_static(LOCAL_CRATE) diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index 720d162ac81..3514829dca7 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -3,22 +3,22 @@ use crate::passes::{self, BoxedResolver, QueryContext}; use rustc::arena::Arena; use rustc::dep_graph::DepGraph; -use rustc::session::config::{OutputFilenames, OutputType}; -use rustc::session::Session; use rustc::ty::steal::Steal; use rustc::ty::{GlobalCtxt, ResolverOutputs}; use rustc::util::common::ErrorReported; +use rustc_ast::{self, ast}; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_data_structures::sync::{Lrc, Once, WorkerLocal}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::Crate; use rustc_incremental::DepGraphFuture; use rustc_lint::LintStore; +use rustc_session::config::{OutputFilenames, OutputType}; +use rustc_session::Session; use std::any::Any; use std::cell::{Ref, RefCell, RefMut}; use std::mem; use std::rc::Rc; -use syntax::{self, ast}; /// Represent the result of a query. /// This result can be stolen with the `take` method and generated with the `compute` method. @@ -340,7 +340,7 @@ impl Compiler { if self.session().opts.debugging_opts.query_stats { if let Ok(gcx) = queries.global_ctxt() { - gcx.peek().print_stats(); + gcx.peek_mut().print_stats(); } } diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index b4e4310cc71..58b8b628de6 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -2,23 +2,22 @@ extern crate getopts; use crate::interface::parse_cfgspecs; -use rustc::lint::Level; use rustc::middle::cstore; -use rustc::session::config::{build_configuration, build_session_options, to_crate_config}; -use rustc::session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes}; -use rustc::session::config::{ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath, TracerMode}; -use rustc::session::config::{Externs, OutputType, OutputTypes, SymbolManglingVersion}; -use rustc::session::search_paths::SearchPath; -use rustc::session::{build_session, Session}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; +use rustc_session::config::{build_configuration, build_session_options, to_crate_config}; +use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes}; +use rustc_session::config::{ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath}; +use rustc_session::config::{Externs, OutputType, OutputTypes, SymbolManglingVersion, TracerMode}; +use rustc_session::lint::Level; +use rustc_session::search_paths::SearchPath; +use rustc_session::{build_session, Session}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel}; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; use std::path::PathBuf; -use syntax; type CfgSpecs = FxHashSet<(String, Option)>; @@ -64,7 +63,7 @@ fn mk_map(entries: Vec<(K, V)>) -> BTreeMap { // When the user supplies --test we should implicitly supply --cfg test #[test] fn test_switch_implies_cfg_test() { - syntax::with_default_globals(|| { + rustc_ast::with_default_globals(|| { let matches = optgroups().parse(&["--test".to_string()]).unwrap(); let (sess, cfg) = mk_session(matches); let cfg = build_configuration(&sess, to_crate_config(cfg)); @@ -75,7 +74,7 @@ fn test_switch_implies_cfg_test() { // When the user supplies --test and --cfg test, don't implicitly add another --cfg test #[test] fn test_switch_implies_cfg_test_unless_cfg_test() { - syntax::with_default_globals(|| { + rustc_ast::with_default_globals(|| { let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap(); let (sess, cfg) = mk_session(matches); let cfg = build_configuration(&sess, to_crate_config(cfg)); @@ -87,20 +86,20 @@ fn test_switch_implies_cfg_test_unless_cfg_test() { #[test] fn test_can_print_warnings() { - syntax::with_default_globals(|| { + rustc_ast::with_default_globals(|| { let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap(); let (sess, _) = mk_session(matches); assert!(!sess.diagnostic().can_emit_warnings()); }); - syntax::with_default_globals(|| { + rustc_ast::with_default_globals(|| { let matches = optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap(); let (sess, _) = mk_session(matches); assert!(sess.diagnostic().can_emit_warnings()); }); - syntax::with_default_globals(|| { + rustc_ast::with_default_globals(|| { let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap(); let (sess, _) = mk_session(matches); assert!(sess.diagnostic().can_emit_warnings()); diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 659323d1c25..5c4de9e7155 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -1,6 +1,10 @@ use log::info; -use rustc::lint; use rustc::ty; +use rustc_ast::ast::{AttrVec, BlockCheckMode}; +use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *}; +use rustc_ast::ptr::P; +use rustc_ast::util::lev_distance::find_best_match_for_name; +use rustc_ast::{self, ast}; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -13,7 +17,7 @@ use rustc_metadata::dynamic_lib::DynamicLibrary; use rustc_resolve::{self, Resolver}; use rustc_session as session; use rustc_session::config::{ErrorOutputType, Input, OutputFilenames}; -use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; +use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer}; use rustc_session::parse::CrateConfig; use rustc_session::CrateDisambiguator; use rustc_session::{config, early_error, filesearch, DiagnosticOutput, Session}; @@ -29,11 +33,6 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex, Once}; #[cfg(not(parallel_compiler))] use std::{panic, thread}; -use syntax::ast::{AttrVec, BlockCheckMode}; -use syntax::mut_visit::{visit_clobber, MutVisitor, *}; -use syntax::ptr::P; -use syntax::util::lev_distance::find_best_match_for_name; -use syntax::{self, ast}; /// Adds `target_feature = "..."` cfgs for a variety of platform /// specific features (SSE, NEON etc.). @@ -49,7 +48,7 @@ pub fn add_configuration( cfg.extend(codegen_backend.target_features(sess).into_iter().map(|feat| (tf, Some(feat)))); - if sess.crt_static_feature() { + if sess.crt_static_feature(None) { cfg.insert((tf, Some(Symbol::intern("crt-static")))); } } @@ -147,7 +146,7 @@ pub fn spawn_thread_pool R + Send, R: Send>( crate::callbacks::setup_callbacks(); scoped_thread(cfg, || { - syntax::with_globals(edition, || { + rustc_ast::with_globals(edition, || { ty::tls::GCX_PTR.set(&Lock::new(0), || { if let Some(stderr) = stderr { io::set_panic(Some(box Sink(stderr.clone()))); @@ -183,15 +182,15 @@ pub fn spawn_thread_pool R + Send, R: Send>( let with_pool = move |pool: &ThreadPool| pool.install(move || f()); - syntax::with_globals(edition, || { - syntax::GLOBALS.with(|syntax_globals| { + rustc_ast::with_globals(edition, || { + rustc_ast::GLOBALS.with(|syntax_globals| { rustc_span::GLOBALS.with(|rustc_span_globals| { // The main handler runs for each Rayon worker thread and sets up // the thread local rustc uses. syntax_globals and rustc_span_globals are // captured and set on the new threads. ty::tls::with_thread_locals sets up - // thread local callbacks from libsyntax + // thread local callbacks from librustc_ast let main_handler = move |thread: ThreadBuilder| { - syntax::GLOBALS.set(syntax_globals, || { + rustc_ast::GLOBALS.set(syntax_globals, || { rustc_span::GLOBALS.set(rustc_span_globals, || { if let Some(stderr) = stderr { io::set_panic(Some(box Sink(stderr.clone()))); @@ -244,7 +243,7 @@ pub fn get_codegen_backend(sess: &Session) -> Box { .as_ref() .unwrap_or(&sess.target.target.options.codegen_backend); let backend = match &codegen_name[..] { - filename if filename.contains(".") => load_backend_from_dylib(filename.as_ref()), + filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()), codegen_name => get_builtin_codegen_backend(codegen_name), }; @@ -426,7 +425,7 @@ pub(crate) fn check_attr_crate_type(attrs: &[ast::Attribute], lint_buffer: &mut for a in attrs.iter() { if a.check_name(sym::crate_type) { if let Some(n) = a.value_str() { - if let Some(_) = categorize_crate_type(n) { + if categorize_crate_type(n).is_some() { return; } @@ -620,8 +619,8 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> { ret } - fn should_ignore_fn(ret_ty: &ast::FunctionRetTy) -> bool { - if let ast::FunctionRetTy::Ty(ref ty) = ret_ty { + fn should_ignore_fn(ret_ty: &ast::FnRetTy) -> bool { + if let ast::FnRetTy::Ty(ref ty) = ret_ty { fn involves_impl_trait(ty: &ast::Ty) -> bool { match ty.kind { ast::TyKind::ImplTrait(..) => true, @@ -639,7 +638,7 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> { ast::GenericArg::Type(ty) => Some(ty), _ => None, }); - any_involves_impl_trait(types.into_iter()) + any_involves_impl_trait(types) || data.constraints.iter().any(|c| match c.kind { ast::AssocTyConstraintKind::Bound { .. } => true, ast::AssocTyConstraintKind::Equality { ref ty } => { @@ -677,7 +676,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { fn visit_item_kind(&mut self, i: &mut ast::ItemKind) { let is_const = match i { ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true, - ast::ItemKind::Fn(ref sig, _, _) => Self::is_sig_const(sig), + ast::ItemKind::Fn(_, ref sig, _, _) => Self::is_sig_const(sig), _ => false, }; self.run(is_const, |s| noop_visit_item_kind(i, s)) @@ -686,7 +685,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { fn flat_map_trait_item(&mut self, i: P) -> SmallVec<[P; 1]> { let is_const = match i.kind { ast::AssocItemKind::Const(..) => true, - ast::AssocItemKind::Fn(ref sig, _) => Self::is_sig_const(sig), + ast::AssocItemKind::Fn(_, ref sig, _, _) => Self::is_sig_const(sig), _ => false, }; self.run(is_const, |s| noop_flat_map_assoc_item(i, s)) @@ -780,7 +779,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { // in general the pretty printer processes unexpanded code, so // we override the default `visit_mac` method which panics. - fn visit_mac(&mut self, mac: &mut ast::Mac) { + fn visit_mac(&mut self, mac: &mut ast::MacCall) { noop_visit_mac(mac, self) } } diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs index 969ce9b06e8..25334461a11 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/src/librustc_lexer/src/lib.rs @@ -35,7 +35,7 @@ impl Token { } } -/// Enum represening common lexeme types. +/// Enum representing common lexeme types. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum TokenKind { // Multi-char tokens: diff --git a/src/librustc_lexer/src/unescape.rs b/src/librustc_lexer/src/unescape.rs index 4f5e03d008c..c51bf735fa7 100644 --- a/src/librustc_lexer/src/unescape.rs +++ b/src/librustc_lexer/src/unescape.rs @@ -17,7 +17,7 @@ pub enum EscapeError { /// Escaped '\' character without continuation. LoneSlash, - /// Invalid escape characted (e.g. '\z'). + /// Invalid escape character (e.g. '\z'). InvalidEscape, /// Raw '\r' encountered. BareCarriageReturn, @@ -43,7 +43,7 @@ pub enum EscapeError { UnclosedUnicodeEscape, /// '\u{_12}' LeadingUnderscoreUnicodeEscape, - /// More than 6 charactes in '\u{..}', e.g. '\u{10FFFF_FF}' + /// More than 6 characters in '\u{..}', e.g. '\u{10FFFF_FF}' OverlongUnicodeEscape, /// Invalid in-bound unicode character code, e.g. '\u{DFFF}'. LoneSurrogateUnicodeEscape, diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 27df0f904e4..9785af5eab2 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -17,9 +17,11 @@ rustc_attr = { path = "../librustc_attr" } rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } rustc_target = { path = "../librustc_target" } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_feature = { path = "../librustc_feature" } rustc_index = { path = "../librustc_index" } rustc_session = { path = "../librustc_session" } +rustc_infer = { path = "../librustc_infer" } +rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 93fca43d67c..408031028b1 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -22,10 +22,12 @@ //! `late_lint_methods!` invocation in `lib.rs`. use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; -use rustc::hir::map::Map; use rustc::lint::LintDiagnosticBuilder; -use rustc::traits::misc::can_type_implement_copy; use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt}; +use rustc_ast::ast::{self, Expr}; +use rustc_ast::attr::{self, HasAttrs}; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder}; @@ -41,10 +43,7 @@ use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{BytePos, Span}; -use syntax::ast::{self, Expr}; -use syntax::attr::{self, HasAttrs}; -use syntax::tokenstream::{TokenStream, TokenTree}; -use syntax::visit::{FnCtxt, FnKind}; +use rustc_trait_selection::traits::misc::can_type_implement_copy; use crate::nonstandard_style::{method_context, MethodLateContext}; @@ -399,7 +398,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } fn check_crate(&mut self, cx: &LateContext<'_, '_>, krate: &hir::Crate<'_>) { - self.check_missing_docs_attrs(cx, None, &krate.attrs, krate.span, "crate"); + self.check_missing_docs_attrs(cx, None, &krate.item.attrs, krate.item.span, "crate"); for macro_def in krate.exported_macros { let has_doc = macro_def.attrs.iter().any(|a| has_doc(a)); @@ -465,7 +464,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { let desc = match trait_item.kind { hir::TraitItemKind::Const(..) => "an associated constant", - hir::TraitItemKind::Method(..) => "a trait method", + hir::TraitItemKind::Fn(..) => "a trait method", hir::TraitItemKind::Type(..) => "an associated type", }; @@ -486,7 +485,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { let desc = match impl_item.kind { hir::ImplItemKind::Const(..) => "an associated constant", - hir::ImplItemKind::Method(..) => "a method", + hir::ImplItemKind::Fn(..) => "a method", hir::ImplItemKind::TyAlias(_) => "an associated type", hir::ImplItemKind::OpaqueTy(_) => "an associated `impl Trait` type", }; @@ -640,7 +639,7 @@ declare_lint_pass!( impl EarlyLintPass for AnonymousParameters { fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) { match it.kind { - ast::AssocItemKind::Fn(ref sig, _) => { + ast::AssocItemKind::Fn(_, ref sig, _, _) => { for arg in sig.decl.inputs.iter() { match arg.pat.kind { ast::PatKind::Ident(_, ident, None) => { @@ -738,87 +737,59 @@ impl EarlyLintPass for DeprecatedAttr { } } -declare_lint! { - pub UNUSED_DOC_COMMENTS, - Warn, - "detects doc comments that aren't used by rustdoc" -} +fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) { + let mut attrs = attrs.iter().peekable(); -declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); + // Accumulate a single span for sugared doc comments. + let mut sugared_span: Option = None; -impl UnusedDocComment { - fn warn_if_doc( - &self, - cx: &EarlyContext<'_>, - node_span: Span, - node_kind: &str, - is_macro_expansion: bool, - attrs: &[ast::Attribute], - ) { - let mut attrs = attrs.into_iter().peekable(); - - // Accumulate a single span for sugared doc comments. - let mut sugared_span: Option = None; - - while let Some(attr) = attrs.next() { - if attr.is_doc_comment() { - sugared_span = Some( - sugared_span.map_or_else(|| attr.span, |span| span.with_hi(attr.span.hi())), - ); - } + while let Some(attr) = attrs.next() { + if attr.is_doc_comment() { + sugared_span = + Some(sugared_span.map_or_else(|| attr.span, |span| span.with_hi(attr.span.hi()))); + } - if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() { - continue; - } + if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() { + continue; + } - let span = sugared_span.take().unwrap_or_else(|| attr.span); + let span = sugared_span.take().unwrap_or_else(|| attr.span); - if attr.is_doc_comment() || attr.check_name(sym::doc) { - cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { - let mut err = lint.build("unused doc comment"); - err.span_label( - node_span, - format!("rustdoc does not generate documentation for {}", node_kind), - ); - if is_macro_expansion { - err.help( - "to document an item produced by a macro, \ - the macro must produce the documentation as part of its expansion", - ); - } - err.emit(); - }); - } + if attr.is_doc_comment() || attr.check_name(sym::doc) { + cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { + let mut err = lint.build("unused doc comment"); + err.span_label( + node_span, + format!("rustdoc does not generate documentation for {}", node_kind), + ); + err.emit(); + }); } } } impl EarlyLintPass for UnusedDocComment { - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { - if let ast::ItemKind::Mac(..) = item.kind { - self.warn_if_doc(cx, item.span, "macro expansions", true, &item.attrs); - } - } - fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) { - let (kind, is_macro_expansion) = match stmt.kind { - ast::StmtKind::Local(..) => ("statements", false), - ast::StmtKind::Item(..) => ("inner items", false), - ast::StmtKind::Mac(..) => ("macro expansions", true), + let kind = match stmt.kind { + ast::StmtKind::Local(..) => "statements", + ast::StmtKind::Item(..) => "inner items", // expressions will be reported by `check_expr`. - ast::StmtKind::Semi(..) | ast::StmtKind::Expr(..) => return, + ast::StmtKind::Empty + | ast::StmtKind::Semi(_) + | ast::StmtKind::Expr(_) + | ast::StmtKind::MacCall(_) => return, }; - self.warn_if_doc(cx, stmt.span, kind, is_macro_expansion, stmt.kind.attrs()); + warn_if_doc(cx, stmt.span, kind, stmt.kind.attrs()); } fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) { let arm_span = arm.pat.span.with_hi(arm.body.span.hi()); - self.warn_if_doc(cx, arm_span, "match arms", false, &arm.attrs); + warn_if_doc(cx, arm_span, "match arms", &arm.attrs); } fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - self.warn_if_doc(cx, expr.span, "expressions", false, &expr.attrs); + warn_if_doc(cx, expr.span, "expressions", &expr.attrs); } } @@ -1099,9 +1070,9 @@ impl TypeAliasBounds { err: &'a mut DiagnosticBuilder<'db>, } impl<'a, 'db, 'v> Visitor<'v> for WalkAssocTypes<'a, 'db> { - type Map = Map<'v>; + type Map = intravisit::ErasedMap<'v>; - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { intravisit::NestedVisitorMap::None } @@ -1506,7 +1477,7 @@ impl EarlyLintPass for KeywordIdents { fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef, _id: ast::NodeId) { self.check_tokens(cx, mac_def.body.inner_tokens()); } - fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::Mac) { + fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) { self.check_tokens(cx, mac.args.inner_tokens()); } fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: ast::Ident) { @@ -1878,7 +1849,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue { /// Test if this constant is all-0. fn is_zero(expr: &hir::Expr<'_>) -> bool { use hir::ExprKind::*; - use syntax::ast::LitKind::*; + use rustc_ast::ast::LitKind::*; match &expr.kind { Lit(lit) => { if let Int(i, _) = lit.node { @@ -1950,21 +1921,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue { use rustc::ty::TyKind::*; match ty.kind { // Primitive types that don't like 0 as a value. - Ref(..) => Some((format!("references must be non-null"), None)), - Adt(..) if ty.is_box() => Some((format!("`Box` must be non-null"), None)), - FnPtr(..) => Some((format!("function pointers must be non-null"), None)), - Never => Some((format!("the `!` type has no valid value"), None)), + Ref(..) => Some(("references must be non-null".to_string(), None)), + Adt(..) if ty.is_box() => Some(("`Box` must be non-null".to_string(), None)), + FnPtr(..) => Some(("function pointers must be non-null".to_string(), None)), + Never => Some(("the `!` type has no valid value".to_string(), None)), RawPtr(tm) if matches!(tm.ty.kind, Dynamic(..)) => // raw ptr to dyn Trait { - Some((format!("the vtable of a wide raw pointer must be non-null"), None)) + Some(("the vtable of a wide raw pointer must be non-null".to_string(), None)) } // Primitive types with other constraints. Bool if init == InitKind::Uninit => { - Some((format!("booleans must be either `true` or `false`"), None)) + Some(("booleans must be either `true` or `false`".to_string(), None)) } Char if init == InitKind::Uninit => { - Some((format!("characters must be a valid Unicode codepoint"), None)) + Some(("characters must be a valid Unicode codepoint".to_string(), None)) } // Recurse and checks for some compound types. Adt(adt_def, substs) if !adt_def.is_union() => { @@ -1992,7 +1963,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue { } // Now, recurse. match adt_def.variants.len() { - 0 => Some((format!("enums with no variants have no valid value"), None)), + 0 => Some(("enums with no variants have no valid value".to_string(), None)), 1 => { // Struct, or enum with exactly one variant. // Proceed recursively, check all fields. diff --git a/src/librustc_lint/context.rs b/src/librustc_lint/context.rs index 8e8beefa72f..5b7b73b48ec 100644 --- a/src/librustc_lint/context.rs +++ b/src/librustc_lint/context.rs @@ -25,6 +25,8 @@ use rustc::middle::privacy::AccessLevels; use rustc::middle::stability; use rustc::ty::layout::{LayoutError, LayoutOf, TyLayout}; use rustc::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; +use rustc_ast::ast; +use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; use rustc_errors::{struct_span_err, Applicability}; @@ -34,8 +36,6 @@ use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::Session; use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP}; -use syntax::ast; -use syntax::util::lev_distance::find_best_match_for_name; use std::slice; @@ -335,7 +335,7 @@ impl LintStore { lint_name.to_string() }; // If the lint was scoped with `tool::` check if the tool lint exists - if let Some(_) = tool_name { + if tool_name.is_some() { match self.by_name.get(&complete_name) { None => match self.lint_groups.get(&*complete_name) { None => return CheckLintNameResult::Tool(Err((None, String::new()))), @@ -369,7 +369,7 @@ impl LintStore { return if *silent { CheckLintNameResult::Ok(&lint_ids) } else { - CheckLintNameResult::Tool(Err((Some(&lint_ids), name.to_string()))) + CheckLintNameResult::Tool(Err((Some(&lint_ids), (*name).to_string()))) }; } CheckLintNameResult::Ok(&lint_ids) @@ -404,7 +404,7 @@ impl LintStore { return if *silent { CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name))) } else { - CheckLintNameResult::Tool(Err((Some(&lint_ids), name.to_string()))) + CheckLintNameResult::Tool(Err((Some(&lint_ids), (*name).to_string()))) }; } CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name))) @@ -565,6 +565,11 @@ pub trait LintContext: Sized { BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => { stability::deprecation_suggestion(&mut db, suggestion, span) } + BuiltinLintDiagnostics::UnusedDocComment(span) => { + db.span_label(span, "rustdoc does not generate documentation for macros"); + db.help("to document an item produced by a macro, \ + the macro must produce the documentation as part of its expansion"); + } } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); diff --git a/src/librustc_lint/early.rs b/src/librustc_lint/early.rs index c3511590673..34da29c9747 100644 --- a/src/librustc_lint/early.rs +++ b/src/librustc_lint/early.rs @@ -16,11 +16,11 @@ use crate::context::{EarlyContext, LintContext, LintStore}; use crate::passes::{EarlyLintPass, EarlyLintPassObject}; -use rustc_session::lint::{LintBuffer, LintPass}; +use rustc_ast::ast; +use rustc_ast::visit as ast_visit; +use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_session::Session; use rustc_span::Span; -use syntax::ast; -use syntax::visit as ast_visit; use log::debug; use std::slice; @@ -37,13 +37,7 @@ struct EarlyContextAndPass<'a, T: EarlyLintPass> { impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { fn check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { - let rustc_session::lint::BufferedEarlyLint { - span, - msg, - node_id: _, - lint_id, - diagnostic, - } = early_lint; + let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint; self.context.lookup_with_diagnostics( lint_id.lint, Some(span), @@ -249,9 +243,9 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> self.check_id(id); } - fn visit_mac(&mut self, mac: &'a ast::Mac) { + fn visit_mac(&mut self, mac: &'a ast::MacCall) { // FIXME(#54110): So, this setup isn't really right. I think - // that (a) the libsyntax visitor ought to be doing this as + // that (a) the librustc_ast visitor ought to be doing this as // part of `walk_mac`, and (b) we should be calling // `visit_path`, *but* that would require a `NodeId`, and I // want to get #53686 fixed quickly. -nmatsakis @@ -326,11 +320,9 @@ pub fn check_ast_crate( lint_buffer: Option, builtin_lints: T, ) { - let mut passes: Vec<_> = if pre_expansion { - lint_store.pre_expansion_passes.iter().map(|p| (p)()).collect() - } else { - lint_store.early_passes.iter().map(|p| (p)()).collect() - }; + let passes = + if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes }; + let mut passes: Vec<_> = passes.iter().map(|p| (p)()).collect(); let mut buffered = lint_buffer.unwrap_or_default(); if !sess.opts.debugging_opts.no_interleave_lints { diff --git a/src/librustc_lint/internal.rs b/src/librustc_lint/internal.rs index 78752619112..d8c685f2b22 100644 --- a/src/librustc_lint/internal.rs +++ b/src/librustc_lint/internal.rs @@ -2,13 +2,13 @@ //! Clippy. use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use rustc_ast::ast::{Ident, Item, ItemKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind}; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::symbol::{sym, Symbol}; -use syntax::ast::{Ident, Item, ItemKind}; declare_tool_lint! { pub rustc::DEFAULT_HASH_TYPES, @@ -140,7 +140,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind { } } TyKind::Rptr(_, MutTy { ty: inner_ty, mutbl: Mutability::Not }) => { - if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner_def_id()) { + if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) { if cx.tcx.impl_trait_ref(impl_did).is_some() { return; } diff --git a/src/librustc_lint/late.rs b/src/librustc_lint/late.rs index b3d5cdf15c9..d2cc5510603 100644 --- a/src/librustc_lint/late.rs +++ b/src/librustc_lint/late.rs @@ -17,6 +17,8 @@ use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore}; use rustc::hir::map::Map; use rustc::ty::{self, TyCtxt}; +use rustc_ast::ast; +use rustc_ast::walk_list; use rustc_data_structures::sync::{join, par_iter, ParallelIterator}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -24,8 +26,6 @@ use rustc_hir::intravisit as hir_visit; use rustc_hir::intravisit::Visitor; use rustc_session::lint::LintPass; use rustc_span::Span; -use syntax::ast; -use syntax::walk_list; use log::debug; use std::any::Any; @@ -33,7 +33,7 @@ use std::slice; /// Extract the `LintStore` from the query context. /// This function exists because we've erased `LintStore` as `dyn Any` in the context. -crate fn unerased_lint_store<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx LintStore { +crate fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore { let store: &dyn Any = &*tcx.lint_store; store.downcast_ref().unwrap() } @@ -99,8 +99,8 @@ impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> hir_visit::Visitor<'tcx> /// Because lints are scoped lexically, we want to walk nested /// items in the context of the outer item, so enable /// deep-walking. - fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, Self::Map> { - hir_visit::NestedVisitorMap::All(&self.context.tcx.hir()) + fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap { + hir_visit::NestedVisitorMap::All(self.context.tcx.hir()) } fn visit_nested_body(&mut self, body: hir::BodyId) { @@ -419,7 +419,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc let mut cx = LateContextAndPass { context, pass }; // Visit the whole crate. - cx.with_lint_attrs(hir::CRATE_HIR_ID, &krate.attrs, |cx| { + cx.with_lint_attrs(hir::CRATE_HIR_ID, &krate.item.attrs, |cx| { // since the root module isn't visited as an item (because it isn't an // item), warn for it here. lint_callback!(cx, check_crate, krate); diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index da449ed42fd..2062f9499ae 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -5,6 +5,9 @@ use rustc::lint::LintDiagnosticBuilder; use rustc::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource}; use rustc::ty::query::Providers; use rustc::ty::TyCtxt; +use rustc_ast::ast; +use rustc_ast::attr; +use rustc_ast::unwrap_or; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, Applicability}; @@ -16,9 +19,6 @@ use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::source_map::MultiSpan; use rustc_span::symbol::{sym, Symbol}; -use syntax::ast; -use syntax::attr; -use syntax::unwrap_or; use std::cmp; @@ -29,7 +29,7 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap { let mut builder = LintLevelMapBuilder { levels, tcx, store }; let krate = tcx.hir().krate(); - let push = builder.levels.push(&krate.attrs, &store); + let push = builder.levels.push(&krate.item.attrs, &store); builder.levels.register_id(hir::CRATE_HIR_ID); for macro_def in krate.exported_macros { builder.levels.register_id(macro_def.hir_id); @@ -375,12 +375,12 @@ impl<'s> LintLevelsBuilder<'s> { } let prev = self.cur; - if specs.len() > 0 { + if !specs.is_empty() { self.cur = self.sets.list.len() as u32; - self.sets.list.push(LintSet::Node { specs: specs, parent: prev }); + self.sets.list.push(LintSet::Node { specs, parent: prev }); } - BuilderPush { prev: prev, changed: prev != self.cur } + BuilderPush { prev, changed: prev != self.cur } } /// Called after `push` when the scope of a set of attributes are exited. @@ -438,8 +438,8 @@ impl LintLevelMapBuilder<'_, '_> { impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> { type Map = Map<'tcx>; - fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, Self::Map> { - intravisit::NestedVisitorMap::All(&self.tcx.hir()) + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::All(self.tcx.hir()) } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 2204e104803..825ac04bc09 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -55,6 +55,7 @@ mod unused; use rustc::ty::query::Providers; use rustc::ty::TyCtxt; +use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_session::lint::builtin::{ @@ -62,7 +63,6 @@ use rustc_session::lint::builtin::{ INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS, }; use rustc_span::Span; -use syntax::ast; use array_into_iter::ArrayIntoIter; use builtin::*; @@ -94,7 +94,7 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: DefId) { macro_rules! pre_expansion_lint_passes { ($macro:path, $args:tt) => { - $macro!($args, [KeywordIdents: KeywordIdents, UnusedDocComment: UnusedDocComment,]); + $macro!($args, [KeywordIdents: KeywordIdents,]); }; } @@ -113,7 +113,8 @@ macro_rules! early_lint_passes { WhileTrue: WhileTrue, NonAsciiIdents: NonAsciiIdents, IncompleteFeatures: IncompleteFeatures, - RedundantSemicolon: RedundantSemicolon, + RedundantSemicolons: RedundantSemicolons, + UnusedDocComment: UnusedDocComment, ] ); }; @@ -273,7 +274,8 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { UNUSED_EXTERN_CRATES, UNUSED_FEATURES, UNUSED_LABELS, - UNUSED_PARENS + UNUSED_PARENS, + REDUNDANT_SEMICOLONS ); add_lint_group!( @@ -305,6 +307,8 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { store.register_renamed("unstable_name_collision", "unstable_name_collisions"); store.register_renamed("unused_doc_comment", "unused_doc_comments"); store.register_renamed("async_idents", "keyword_idents"); + store.register_renamed("exceeding_bitshifts", "arithmetic_overflow"); + store.register_renamed("redundant_semicolon", "redundant_semicolons"); store.register_removed("unknown_features", "replaced by an error"); store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate"); store.register_removed("negate_unsigned", "cast a signed value instead"); diff --git a/src/librustc_lint/non_ascii_idents.rs b/src/librustc_lint/non_ascii_idents.rs index a0ca7ad1860..470fac2675b 100644 --- a/src/librustc_lint/non_ascii_idents.rs +++ b/src/librustc_lint/non_ascii_idents.rs @@ -1,5 +1,5 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; -use syntax::ast; +use rustc_ast::ast; declare_lint! { pub NON_ASCII_IDENTS, diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index 8c58f2ba4c0..afab55358d9 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -1,5 +1,6 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc::ty; +use rustc_ast::ast; use rustc_attr as attr; use rustc_errors::Applicability; use rustc_hir as hir; @@ -9,7 +10,6 @@ use rustc_hir::{GenericParamKind, PatKind}; use rustc_span::symbol::sym; use rustc_span::{symbol::Ident, BytePos, Span}; use rustc_target::spec::abi::Abi; -use syntax::ast; #[derive(PartialEq)] pub enum MethodLateContext { @@ -343,7 +343,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { } fn check_trait_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::TraitItem<'_>) { - if let hir::TraitItemKind::Method(_, hir::TraitMethod::Required(pnames)) = item.kind { + if let hir::TraitItemKind::Fn(_, hir::TraitFn::Required(pnames)) = item.kind { self.check_snake_case(cx, "trait method", &item.ident); for param_name in pnames { self.check_snake_case(cx, "variable", param_name); diff --git a/src/librustc_lint/passes.rs b/src/librustc_lint/passes.rs index 36de625cafa..ace15471445 100644 --- a/src/librustc_lint/passes.rs +++ b/src/librustc_lint/passes.rs @@ -1,11 +1,11 @@ use crate::context::{EarlyContext, LateContext}; +use rustc_ast::ast; use rustc_data_structures::sync; use rustc_hir as hir; use rustc_session::lint::builtin::HardwiredLints; use rustc_session::lint::LintPass; use rustc_span::Span; -use syntax::ast; #[macro_export] macro_rules! late_lint_methods { @@ -179,9 +179,9 @@ macro_rules! early_lint_methods { fn check_where_predicate(a: &ast::WherePredicate); fn check_poly_trait_ref(a: &ast::PolyTraitRef, b: &ast::TraitBoundModifier); - fn check_fn(a: syntax::visit::FnKind<'_>, c: Span, d_: ast::NodeId); + fn check_fn(a: rustc_ast::visit::FnKind<'_>, c: Span, d_: ast::NodeId); fn check_fn_post( - a: syntax::visit::FnKind<'_>, + a: rustc_ast::visit::FnKind<'_>, c: Span, d: ast::NodeId ); @@ -198,7 +198,7 @@ macro_rules! early_lint_methods { fn check_path(a: &ast::Path, b: ast::NodeId); fn check_attribute(a: &ast::Attribute); fn check_mac_def(a: &ast::MacroDef, b: ast::NodeId); - fn check_mac(a: &ast::Mac); + fn check_mac(a: &ast::MacCall); /// Called when entering a syntax node that can have lint attributes such /// as `#[allow(...)]`. Called with *all* the attributes of that node. diff --git a/src/librustc_lint/redundant_semicolon.rs b/src/librustc_lint/redundant_semicolon.rs index 68cb0b54f56..0f807cd497e 100644 --- a/src/librustc_lint/redundant_semicolon.rs +++ b/src/librustc_lint/redundant_semicolon.rs @@ -1,50 +1,41 @@ use crate::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_ast::ast::{Block, StmtKind}; use rustc_errors::Applicability; -use syntax::ast::{ExprKind, Stmt, StmtKind}; +use rustc_span::Span; declare_lint! { - pub REDUNDANT_SEMICOLON, + pub REDUNDANT_SEMICOLONS, Warn, "detects unnecessary trailing semicolons" } -declare_lint_pass!(RedundantSemicolon => [REDUNDANT_SEMICOLON]); +declare_lint_pass!(RedundantSemicolons => [REDUNDANT_SEMICOLONS]); -impl EarlyLintPass for RedundantSemicolon { - fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) { - if let StmtKind::Semi(expr) = &stmt.kind { - if let ExprKind::Tup(ref v) = &expr.kind { - if v.is_empty() { - // Strings of excess semicolons are encoded as empty tuple expressions - // during the parsing stage, so we check for empty tuple expressions - // which span only semicolons - if let Ok(source_str) = cx.sess().source_map().span_to_snippet(stmt.span) { - if source_str.chars().all(|c| c == ';') { - let multiple = (stmt.span.hi() - stmt.span.lo()).0 > 1; - let msg = if multiple { - "unnecessary trailing semicolons" - } else { - "unnecessary trailing semicolon" - }; - cx.struct_span_lint(REDUNDANT_SEMICOLON, stmt.span, |lint| { - let mut err = lint.build(&msg); - let suggest_msg = if multiple { - "remove these semicolons" - } else { - "remove this semicolon" - }; - err.span_suggestion( - stmt.span, - &suggest_msg, - String::new(), - Applicability::MaybeIncorrect, - ); - err.emit(); - }); - } - } - } +impl EarlyLintPass for RedundantSemicolons { + fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { + let mut seq = None; + for stmt in block.stmts.iter() { + match (&stmt.kind, &mut seq) { + (StmtKind::Empty, None) => seq = Some((stmt.span, false)), + (StmtKind::Empty, Some(seq)) => *seq = (seq.0.to(stmt.span), true), + (_, seq) => maybe_lint_redundant_semis(cx, seq), } } + maybe_lint_redundant_semis(cx, &mut seq); + } +} + +fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) { + if let Some((span, multiple)) = seq.take() { + cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| { + let (msg, rem) = if multiple { + ("unnecessary trailing semicolons", "remove these semicolons") + } else { + ("unnecessary trailing semicolon", "remove this semicolon") + }; + lint.build(msg) + .span_suggestion(span, rem, String::new(), Applicability::MaybeIncorrect) + .emit(); + }); } } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 5ffa9c1747f..4949c93d45e 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -5,6 +5,7 @@ use rustc::mir::interpret::{sign_extend, truncate}; use rustc::ty::layout::{self, IntegerExt, LayoutOf, SizeSkeleton, VariantIdx}; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; +use rustc_ast::ast; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -16,7 +17,6 @@ use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi::Abi; -use syntax::ast; use log::debug; use std::cmp; @@ -83,9 +83,9 @@ fn lint_overflowing_range_endpoint<'a, 'tcx>( // We need to preserve the literal's suffix, // as it may determine typing information. let suffix = match lit.node { - LitKind::Int(_, LitIntType::Signed(s)) => format!("{}", s.name_str()), - LitKind::Int(_, LitIntType::Unsigned(s)) => format!("{}", s.name_str()), - LitKind::Int(_, LitIntType::Unsuffixed) => "".to_owned(), + LitKind::Int(_, LitIntType::Signed(s)) => s.name_str().to_string(), + LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str().to_string(), + LitKind::Int(_, LitIntType::Unsuffixed) => "".to_string(), _ => bug!(), }; let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); @@ -165,7 +165,7 @@ fn report_bin_hex_error( let mut err = lint.build(&format!("literal out of range for {}", t)); err.note(&format!( "the literal `{}` (decimal `{}`) does not fit into \ - an `{}` and will become `{}{}`", + the type `{}` and will become `{}{}`", repr_str, val, t, actually, t )); if let Some(sugg_ty) = get_type_suggestion(&cx.tables.node_type(expr.hir_id), val, negative) @@ -194,8 +194,8 @@ fn report_bin_hex_error( // // No suggestion for: `isize`, `usize`. fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static str> { - use syntax::ast::IntTy::*; - use syntax::ast::UintTy::*; + use rustc_ast::ast::IntTy::*; + use rustc_ast::ast::UintTy::*; macro_rules! find_fit { ($ty:expr, $val:expr, $negative:expr, $($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => { @@ -242,7 +242,7 @@ fn lint_int_literal<'a, 'tcx>( v: u128, ) { let int_type = t.normalize(cx.sess().target.ptr_width); - let (_, max) = int_ty_range(int_type); + let (min, max) = int_ty_range(int_type); let max = max as u128; let negative = type_limits.negated_expr_id == e.hir_id; @@ -267,7 +267,19 @@ fn lint_int_literal<'a, 'tcx>( } cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { - lint.build(&format!("literal out of range for `{}`", t.name_str())).emit() + lint.build(&format!("literal out of range for `{}`", t.name_str())) + .note(&format!( + "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`", + cx.sess() + .source_map() + .span_to_snippet(lit.span) + .ok() + .expect("must get snippet from literal"), + t.name_str(), + min, + max, + )) + .emit(); }); } } @@ -320,7 +332,19 @@ fn lint_uint_literal<'a, 'tcx>( return; } cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { - lint.build(&format!("literal out of range for `{}`", t.name_str())).emit() + lint.build(&format!("literal out of range for `{}`", t.name_str())) + .note(&format!( + "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`", + cx.sess() + .source_map() + .span_to_snippet(lit.span) + .ok() + .expect("must get snippet from literal"), + t.name_str(), + min, + max, + )) + .emit() }); } } @@ -352,7 +376,17 @@ fn lint_literal<'a, 'tcx>( }; if is_infinite == Ok(true) { cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| { - lint.build(&format!("literal out of range for `{}`", t.name_str())).emit() + lint.build(&format!("literal out of range for `{}`", t.name_str())) + .note(&format!( + "the literal `{}` does not fit into the type `{}` and will be converted to `std::{}::INFINITY`", + cx.sess() + .source_map() + .span_to_snippet(lit.span) + .expect("must get snippet from literal"), + t.name_str(), + t.name_str(), + )) + .emit(); }); } } @@ -953,7 +987,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false); } - if let hir::FunctionRetTy::Return(ref ret_hir) = decl.output { + if let hir::FnRetTy::Return(ref ret_hir) = decl.output { let ret_ty = sig.output(); if !ret_ty.is_unit() { self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, false); @@ -998,10 +1032,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { let ty = cx.tcx.erase_regions(&t); let layout = match cx.layout_of(ty) { Ok(layout) => layout, - Err(ty::layout::LayoutError::Unknown(_)) => return, - Err(err @ ty::layout::LayoutError::SizeOverflow(_)) => { - bug!("failed to get layout for `{}`: {}", t, err); - } + Err(ty::layout::LayoutError::Unknown(_)) + | Err(ty::layout::LayoutError::SizeOverflow(_)) => return, }; let (variants, tag) = match layout.variants { layout::Variants::Multiple { diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 480df99a01e..229740615f7 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -1,6 +1,9 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc::ty::adjustment; use rustc::ty::{self, Ty}; +use rustc_ast::ast; +use rustc_ast::attr; +use rustc_ast::util::parser; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, Applicability}; @@ -12,9 +15,6 @@ use rustc_session::lint::builtin::UNUSED_ATTRIBUTES; use rustc_span::symbol::Symbol; use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span}; -use syntax::ast; -use syntax::attr; -use syntax::util::parser; use log::debug; @@ -54,7 +54,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { match callee.kind { hir::ExprKind::Path(ref qpath) => { match cx.tables.qpath_res(qpath, callee.hir_id) { - Res::Def(DefKind::Fn, def_id) | Res::Def(DefKind::Method, def_id) => { + Res::Def(DefKind::Fn, def_id) | Res::Def(DefKind::AssocFn, def_id) => { Some(def_id) } // `Res::Local` if it was a closure, for which we @@ -125,7 +125,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { plural_len: usize, ) -> bool { if ty.is_unit() - || cx.tcx.is_ty_uninhabited_from(cx.tcx.hir().get_module_parent(expr.hir_id), ty) + || cx.tcx.is_ty_uninhabited_from( + cx.tcx.parent_module(expr.hir_id).to_def_id(), + ty, + cx.param_env, + ) { return true; } @@ -469,7 +473,7 @@ impl UnusedParens { impl EarlyLintPass for UnusedParens { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - use syntax::ast::ExprKind::*; + use rustc_ast::ast::ExprKind::*; let (value, msg, followed_by_block, left_pos, right_pos) = match e.kind { Let(ref pat, ..) => { self.check_unused_parens_pat(cx, pat, false, false); @@ -539,7 +543,7 @@ impl EarlyLintPass for UnusedParens { // Do not lint on `(..)` as that will result in the other arms being useless. Paren(_) // The other cases do not contain sub-patterns. - | Wild | Rest | Lit(..) | Mac(..) | Range(..) | Ident(.., None) | Path(..) => return, + | Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => return, // These are list-like patterns; parens can always be removed. TupleStruct(_, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { self.check_unused_parens_pat(cx, p, false, false); @@ -603,7 +607,7 @@ impl EarlyLintPass for UnusedParens { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { use ast::ItemKind::*; - if let Const(.., ref expr) | Static(.., ref expr) = item.kind { + if let Const(.., Some(expr)) | Static(.., Some(expr)) = &item.kind { self.check_unused_parens_expr(cx, expr, "assigned value", false, None, None); } } diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 405ce0307cd..9b4f03b3fb6 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -178,7 +178,7 @@ fn main() { for lib in output(&mut cmd).split_whitespace() { let name = if lib.starts_with("-l") { &lib[2..] - } else if lib.starts_with("-") { + } else if lib.starts_with('-') { &lib[1..] } else if Path::new(lib).exists() { // On MSVC llvm-config will print the full name to libraries, but diff --git a/src/librustc_macros/src/hash_stable.rs b/src/librustc_macros/src/hash_stable.rs index e6f457dd663..dc6ae961e5a 100644 --- a/src/librustc_macros/src/hash_stable.rs +++ b/src/librustc_macros/src/hash_stable.rs @@ -1,7 +1,6 @@ use proc_macro2::{self, Ident}; use quote::quote; use syn::{self, parse_quote, Meta, NestedMeta}; -use synstructure; struct Attributes { ignore: bool, diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index 294cdb7643f..56b7be2f7e2 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -33,6 +33,9 @@ enum QueryModifier { /// The description of the query. Desc(Option, Punctuated), + /// Use this type for the in-memory cache. + Storage(Type), + /// Cache the query to disk if the `Expr` returns true. Cache(Option<(IdentOrWild, IdentOrWild)>, Block), @@ -48,13 +51,10 @@ enum QueryModifier { /// Don't hash the result, instead just mark a query red if it runs NoHash, - /// Don't force the query - NoForce, - /// Generate a dep node based on the dependencies of the query Anon, - /// Always evaluate the query, ignoring its depdendencies + /// Always evaluate the query, ignoring its dependencies EvalAlways, } @@ -106,14 +106,15 @@ impl Parse for QueryModifier { let id = args.parse()?; let block = input.parse()?; Ok(QueryModifier::LoadCached(tcx, id, block)) + } else if modifier == "storage" { + let ty = input.parse()?; + Ok(QueryModifier::Storage(ty)) } else if modifier == "fatal_cycle" { Ok(QueryModifier::FatalCycle) } else if modifier == "cycle_delay_bug" { Ok(QueryModifier::CycleDelayBug) } else if modifier == "no_hash" { Ok(QueryModifier::NoHash) - } else if modifier == "no_force" { - Ok(QueryModifier::NoForce) } else if modifier == "anon" { Ok(QueryModifier::Anon) } else if modifier == "eval_always" { @@ -198,6 +199,9 @@ struct QueryModifiers { /// The description of the query. desc: Option<(Option, Punctuated)>, + /// Use this type for the in-memory cache. + storage: Option, + /// Cache the query to disk if the `Block` returns true. cache: Option<(Option<(IdentOrWild, IdentOrWild)>, Block)>, @@ -213,25 +217,22 @@ struct QueryModifiers { /// Don't hash the result, instead just mark a query red if it runs no_hash: bool, - /// Don't force the query - no_force: bool, - /// Generate a dep node based on the dependencies of the query anon: bool, - // Always evaluate the query, ignoring its depdendencies + // Always evaluate the query, ignoring its dependencies eval_always: bool, } /// Process query modifiers into a struct, erroring on duplicates fn process_modifiers(query: &mut Query) -> QueryModifiers { let mut load_cached = None; + let mut storage = None; let mut cache = None; let mut desc = None; let mut fatal_cycle = false; let mut cycle_delay_bug = false; let mut no_hash = false; - let mut no_force = false; let mut anon = false; let mut eval_always = false; for modifier in query.modifiers.0.drain(..) { @@ -242,6 +243,12 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { } load_cached = Some((tcx, id, block)); } + QueryModifier::Storage(ty) => { + if storage.is_some() { + panic!("duplicate modifier `storage` for query `{}`", query.name); + } + storage = Some(ty); + } QueryModifier::Cache(args, expr) => { if cache.is_some() { panic!("duplicate modifier `cache` for query `{}`", query.name); @@ -272,12 +279,6 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { } no_hash = true; } - QueryModifier::NoForce => { - if no_force { - panic!("duplicate modifier `no_force` for query `{}`", query.name); - } - no_force = true; - } QueryModifier::Anon => { if anon { panic!("duplicate modifier `anon` for query `{}`", query.name); @@ -294,12 +295,12 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { } QueryModifiers { load_cached, + storage, cache, desc, fatal_cycle, cycle_delay_bug, no_hash, - no_force, anon, eval_always, } @@ -408,7 +409,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut dep_node_def_stream = quote! {}; let mut dep_node_force_stream = quote! {}; let mut try_load_from_on_disk_cache_stream = quote! {}; - let mut no_force_queries = Vec::new(); let mut cached_queries = quote! {}; for group in groups.0 { @@ -427,19 +427,19 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { cached_queries.extend(quote! { #name, }); - } - if modifiers.cache.is_some() && !modifiers.no_force { try_load_from_on_disk_cache_stream.extend(quote! { DepKind::#name => { - debug_assert!(tcx.dep_graph - .node_color(self) - .map(|c| c.is_green()) - .unwrap_or(false)); - - let key = RecoverKey::recover(tcx, self).unwrap(); - if queries::#name::cache_on_disk(tcx, key, None) { - let _ = tcx.#name(key); + if <#arg as DepNodeParams>::CAN_RECONSTRUCT_QUERY_KEY { + debug_assert!($tcx.dep_graph + .node_color($dep_node) + .map(|c| c.is_green()) + .unwrap_or(false)); + + let key = <#arg as DepNodeParams>::recover($tcx, $dep_node).unwrap(); + if queries::#name::cache_on_disk($tcx, key, None) { + let _ = $tcx.#name(key); + } } } }); @@ -451,6 +451,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { if modifiers.fatal_cycle { attributes.push(quote! { fatal_cycle }); }; + // Pass on the storage modifier + if let Some(ref ty) = modifiers.storage { + attributes.push(quote! { storage(#ty) }); + }; // Pass on the cycle_delay_bug modifier if modifiers.cycle_delay_bug { attributes.push(quote! { cycle_delay_bug }); @@ -480,24 +484,21 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { [#attribute_stream] #name(#arg), }); - if modifiers.no_force { - no_force_queries.push(name.clone()); - } else { - // Add a match arm to force the query given the dep node - dep_node_force_stream.extend(quote! { - DepKind::#name => { - if let Some(key) = RecoverKey::recover($tcx, $dep_node) { + // Add a match arm to force the query given the dep node + dep_node_force_stream.extend(quote! { + DepKind::#name => { + if <#arg as DepNodeParams>::CAN_RECONSTRUCT_QUERY_KEY { + if let Some(key) = <#arg as DepNodeParams>::recover($tcx, $dep_node) { $tcx.force_query::>( key, DUMMY_SP, *$dep_node ); - } else { - return false; + return true; } } - }); - } + } + }); add_query_description_impl(&query, modifiers, &mut query_description_stream); } @@ -507,12 +508,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { }); } - // Add an arm for the no force queries to panic when trying to force them - for query in no_force_queries { - dep_node_force_stream.extend(quote! { - DepKind::#query | - }); - } dep_node_force_stream.extend(quote! { DepKind::Null => { bug!("Cannot force dep node: {:?}", $dep_node) @@ -556,14 +551,9 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { #query_description_stream - impl DepNode { - /// Check whether the query invocation corresponding to the given - /// DepNode is eligible for on-disk-caching. If so, this is method - /// will execute the query corresponding to the given DepNode. - /// Also, as a sanity check, it expects that the corresponding query - /// invocation has been marked as green already. - pub fn try_load_from_on_disk_cache(&self, tcx: TyCtxt<'_>) { - match self.kind { + macro_rules! rustc_dep_node_try_load_from_on_disk_cache { + ($dep_node:expr, $tcx:expr) => { + match $dep_node.kind { #try_load_from_on_disk_cache_stream _ => (), } diff --git a/src/librustc_macros/src/symbols.rs b/src/librustc_macros/src/symbols.rs index feddcd5f994..0f8bc432307 100644 --- a/src/librustc_macros/src/symbols.rs +++ b/src/librustc_macros/src/symbols.rs @@ -103,6 +103,7 @@ pub fn symbols(input: TokenStream) -> TokenStream { #value, }); keyword_stream.extend(quote! { + #[allow(non_upper_case_globals)] pub const #name: Symbol = Symbol::new(#counter); }); counter += 1; @@ -120,6 +121,8 @@ pub fn symbols(input: TokenStream) -> TokenStream { #value, }); symbols_stream.extend(quote! { + #[allow(rustc::default_hash_types)] + #[allow(non_upper_case_globals)] pub const #name: Symbol = Symbol::new(#counter); }); counter += 1; @@ -149,6 +152,7 @@ pub fn symbols(input: TokenStream) -> TokenStream { () => { #symbols_stream + #[allow(non_upper_case_globals)] pub const digits_array: &[Symbol; 10] = &[ #digits_stream ]; diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index a4fdcee5e12..088cba83ef9 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -15,7 +15,6 @@ log = "0.4" memmap = "0.7" smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc = { path = "../librustc" } -rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_attr = { path = "../librustc_attr" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } @@ -24,10 +23,10 @@ rustc_target = { path = "../librustc_target" } rustc_index = { path = "../librustc_index" } rustc_serialize = { path = "../libserialize", package = "serialize" } stable_deref_trait = "1.0.0" -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } rustc_expand = { path = "../librustc_expand" } -rustc_parse = { path = "../librustc_parse" } rustc_span = { path = "../librustc_span" } +rustc_session = { path = "../librustc_session" } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["errhandlingapi", "libloaderapi"] } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4c4383aa603..f20cdfcba15 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -6,23 +6,22 @@ use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob use rustc::hir::map::Definitions; use rustc::middle::cstore::DepKind; use rustc::middle::cstore::{CrateSource, ExternCrate, ExternCrateSource, MetadataLoaderDyn}; -use rustc::session::config; -use rustc::session::search_paths::PathKind; -use rustc::session::{CrateDisambiguator, Session}; use rustc::ty::TyCtxt; +use rustc_ast::expand::allocator::{global_allocator_spans, AllocatorKind}; +use rustc_ast::{ast, attr}; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_errors::struct_span_err; use rustc_expand::base::SyntaxExtension; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_index::vec::IndexVec; +use rustc_session::config; +use rustc_session::search_paths::PathKind; +use rustc_session::{CrateDisambiguator, Session}; use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::{PanicStrategy, TargetTriple}; -use syntax::ast; -use syntax::attr; -use syntax::expand::allocator::{global_allocator_spans, AllocatorKind}; use log::{debug, info, log_enabled}; use proc_macro::bridge::client::ProcMacro; @@ -76,6 +75,21 @@ impl<'a> LoadError<'a> { } } +/// A reference to `CrateMetadata` that can also give access to whole crate store when necessary. +#[derive(Clone, Copy)] +crate struct CrateMetadataRef<'a> { + pub cdata: &'a CrateMetadata, + pub cstore: &'a CStore, +} + +impl std::ops::Deref for CrateMetadataRef<'_> { + type Target = CrateMetadata; + + fn deref(&self) -> &Self::Target { + self.cdata + } +} + fn dump_crates(cstore: &CStore) { info!("resolved crates:"); cstore.iter_crate_data(|cnum, data| { @@ -100,10 +114,11 @@ impl CStore { CrateNum::new(self.metas.len() - 1) } - crate fn get_crate_data(&self, cnum: CrateNum) -> &CrateMetadata { - self.metas[cnum] + crate fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> { + let cdata = self.metas[cnum] .as_ref() - .unwrap_or_else(|| panic!("Failed to get crate data for {:?}", cnum)) + .unwrap_or_else(|| panic!("Failed to get crate data for {:?}", cnum)); + CrateMetadataRef { cdata, cstore: self } } fn set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata) { @@ -217,7 +232,7 @@ impl<'a> CrateLoader<'a> { // We're also sure to compare *paths*, not actual byte slices. The // `source` stores paths which are normalized which may be different // from the strings on the command line. - let source = self.cstore.get_crate_data(cnum).source(); + let source = self.cstore.get_crate_data(cnum).cdata.source(); if let Some(entry) = self.sess.opts.externs.get(&name.as_str()) { // Only use `--extern crate_name=path` here, not `--extern crate_name`. if let Some(mut files) = entry.files() { @@ -463,7 +478,7 @@ impl<'a> CrateLoader<'a> { self.load(&mut locator) .map(|r| (r, None)) .or_else(|| { - dep_kind = DepKind::UnexportedMacrosOnly; + dep_kind = DepKind::MacrosOnly; self.load_proc_macro(&mut locator, path_kind) }) .ok_or_else(move || LoadError::LocatorError(locator))? @@ -473,7 +488,7 @@ impl<'a> CrateLoader<'a> { (LoadResult::Previous(cnum), None) => { let data = self.cstore.get_crate_data(cnum); if data.is_proc_macro_crate() { - dep_kind = DepKind::UnexportedMacrosOnly; + dep_kind = DepKind::MacrosOnly; } data.update_dep_kind(|data_dep_kind| cmp::max(data_dep_kind, dep_kind)); Ok(cnum) @@ -547,9 +562,6 @@ impl<'a> CrateLoader<'a> { "resolving dep crate {} hash: `{}` extra filename: `{}`", dep.name, dep.hash, dep.extra_filename ); - if dep.kind == DepKind::UnexportedMacrosOnly { - return krate; - } let dep_kind = match dep_kind { DepKind::MacrosOnly => DepKind::MacrosOnly, _ => dep.kind, @@ -680,10 +692,7 @@ impl<'a> CrateLoader<'a> { // Sanity check the loaded crate to ensure it is indeed a profiler runtime if !data.is_profiler_runtime() { - self.sess.err(&format!( - "the crate `profiler_builtins` is not \ - a profiler runtime" - )); + self.sess.err("the crate `profiler_builtins` is not a profiler runtime"); } } } @@ -853,7 +862,7 @@ impl<'a> CrateLoader<'a> { None => item.ident.name, }; let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) { - DepKind::UnexportedMacrosOnly + DepKind::MacrosOnly } else { DepKind::Explicit }; @@ -861,11 +870,11 @@ impl<'a> CrateLoader<'a> { let cnum = self.resolve_crate(name, item.span, dep_kind, None); let def_id = definitions.opt_local_def_id(item.id).unwrap(); - let path_len = definitions.def_path(def_id.index).data.len(); + let path_len = definitions.def_path(def_id).data.len(); self.update_extern_crate( cnum, ExternCrate { - src: ExternCrateSource::Extern(def_id), + src: ExternCrateSource::Extern(def_id.to_def_id()), span: item.span, path_len, dependency_of: LOCAL_CRATE, diff --git a/src/librustc_metadata/dependency_format.rs b/src/librustc_metadata/dependency_format.rs index 375f372005f..4cfaf03b7a5 100644 --- a/src/librustc_metadata/dependency_format.rs +++ b/src/librustc_metadata/dependency_format.rs @@ -56,10 +56,10 @@ use crate::creader::CStore; use rustc::middle::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; use rustc::middle::cstore::{self, DepKind}; use rustc::middle::dependency_format::{Dependencies, DependencyList, Linkage}; -use rustc::session::config; use rustc::ty::TyCtxt; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::CrateNum; +use rustc_session::config; use rustc_target::spec::PanicStrategy; crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies { @@ -97,7 +97,9 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: config::CrateType) -> DependencyList { // If the global prefer_dynamic switch is turned off, or the final // executable will be statically linked, prefer static crate linkage. - config::CrateType::Executable if !sess.opts.cg.prefer_dynamic || sess.crt_static() => { + config::CrateType::Executable + if !sess.opts.cg.prefer_dynamic || sess.crt_static(Some(ty)) => + { Linkage::Static } config::CrateType::Executable => Linkage::Dynamic, @@ -129,7 +131,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: config::CrateType) -> DependencyList { // If any are not found, generate some nice pretty errors. if ty == config::CrateType::Staticlib || (ty == config::CrateType::Executable - && sess.crt_static() + && sess.crt_static(Some(ty)) && !sess.target.target.options.crt_static_allows_dylibs) { for &cnum in tcx.crates().iter() { @@ -339,7 +341,7 @@ fn activate_injected_dep( // there's only going to be one allocator in the output. fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { let sess = &tcx.sess; - if list.len() == 0 { + if list.is_empty() { return; } let mut panic_runtime = None; diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index d4cc3c32616..e401dc0f6e7 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -31,7 +31,7 @@ pub mod dynamic_lib; pub mod locator; pub fn validate_crate_name( - sess: Option<&rustc::session::Session>, + sess: Option<&rustc_session::Session>, s: &str, sp: Option, ) { diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 8d018b9bb94..13668b2423f 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -8,7 +8,7 @@ crate fn collect(tcx: TyCtxt<'_>) -> Vec { let mut collector = Collector { args: Vec::new() }; tcx.hir().krate().visit_all_item_likes(&mut collector); - for attr in tcx.hir().krate().attrs.iter() { + for attr in tcx.hir().krate().item.attrs.iter() { if attr.has_name(sym::link_args) { if let Some(linkarg) = attr.value_str() { collector.add_link_args(&linkarg.as_str()); diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 2157b8ce159..1ede629e7ef 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -216,13 +216,13 @@ use crate::creader::Library; use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER}; use rustc::middle::cstore::{CrateSource, MetadataLoader}; -use rustc::session::filesearch::{FileDoesntMatch, FileMatches, FileSearch}; -use rustc::session::search_paths::PathKind; -use rustc::session::{config, CrateDisambiguator, Session}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; use rustc_errors::{struct_span_err, DiagnosticBuilder}; +use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch}; +use rustc_session::search_paths::PathKind; +use rustc_session::{config, CrateDisambiguator, Session}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use rustc_target::spec::{Target, TargetTriple}; @@ -711,7 +711,7 @@ impl<'a> CrateLocator<'a> { // See also #68149 which provides more detail on why emitting the // dependency on the rlib is a bad thing. // - // We currenty do not verify that these other sources are even in sync, + // We currently do not verify that these other sources are even in sync, // and this is arguably a bug (see #10786), but because reading metadata // is quite slow (especially from dylibs) we currently do not read it // from the other crate sources. diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index 2fa9cb099dd..64bbf393ba0 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -1,12 +1,12 @@ use rustc::middle::cstore::{self, NativeLibrary}; -use rustc::session::parse::feature_err; -use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_session::parse::feature_err; +use rustc_session::Session; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_target::spec::abi::Abi; diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 58cf142ab3a..2bf74fe272e 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -1,9 +1,10 @@ // Decoding metadata from a single crate's metadata +use crate::creader::CrateMetadataRef; use crate::rmeta::table::{FixedSizeEncoding, Table}; use crate::rmeta::*; -use rustc::dep_graph::{self, DepNodeIndex}; +use rustc::dep_graph::{self, DepNode, DepNodeIndex}; use rustc::hir::exports::Export; use rustc::hir::map::definitions::DefPathTable; use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash}; @@ -13,36 +14,35 @@ use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::middle::lang_items; use rustc::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc::mir::{self, interpret, BodyAndCache, Promoted}; -use rustc::session::Session; use rustc::ty::codec::TyDecoder; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::common::record_time; +use rustc_ast::ast::{self, Ident}; +use rustc_attr as attr; use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{AtomicCell, Lock, LockGuard, Lrc, Once}; +use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; +use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_index::vec::{Idx, IndexVec}; +use rustc_serialize::{opaque, Decodable, Decoder, SpecializedDecoder}; +use rustc_session::Session; +use rustc_span::source_map::{self, respan, Spanned}; +use rustc_span::symbol::{sym, Symbol}; +use rustc_span::{self, hygiene::MacroKind, BytePos, Pos, Span, DUMMY_SP}; +use log::debug; +use proc_macro::bridge::client::ProcMacro; use std::io; use std::mem; use std::num::NonZeroUsize; use std::u32; -use log::debug; -use proc_macro::bridge::client::ProcMacro; -use rustc_attr as attr; -use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; -use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive}; -use rustc_serialize::{opaque, Decodable, Decoder, SpecializedDecoder}; -use rustc_span::source_map::{self, respan, Spanned}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{self, hygiene::MacroKind, BytePos, Pos, Span, DUMMY_SP}; -use syntax::ast::{self, Ident}; - pub use cstore_impl::{provide, provide_extern}; mod cstore_impl; @@ -125,7 +125,7 @@ struct ImportedSourceFile { pub(super) struct DecodeContext<'a, 'tcx> { opaque: opaque::Decoder<'a>, - cdata: Option<&'a CrateMetadata>, + cdata: Option>, sess: Option<&'tcx Session>, tcx: Option>, @@ -141,7 +141,7 @@ pub(super) struct DecodeContext<'a, 'tcx> { /// Abstract over the various ways one can create metadata decoders. pub(super) trait Metadata<'a, 'tcx>: Copy { fn raw_bytes(self) -> &'a [u8]; - fn cdata(self) -> Option<&'a CrateMetadata> { + fn cdata(self) -> Option> { None } fn sess(self) -> Option<&'tcx Session> { @@ -162,7 +162,7 @@ pub(super) trait Metadata<'a, 'tcx>: Copy { lazy_state: LazyState::NoNode, alloc_decoding_session: self .cdata() - .map(|cdata| cdata.alloc_decoding_state.new_decoding_session()), + .map(|cdata| cdata.cdata.alloc_decoding_state.new_decoding_session()), } } } @@ -185,33 +185,33 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a MetadataBlob, &'tcx Session) { } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadata { +impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadataRef<'a> { fn raw_bytes(self) -> &'a [u8] { self.blob.raw_bytes() } - fn cdata(self) -> Option<&'a CrateMetadata> { - Some(self) + fn cdata(self) -> Option> { + Some(*self) } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, &'tcx Session) { +impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, &'tcx Session) { fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() } - fn cdata(self) -> Option<&'a CrateMetadata> { - Some(self.0) + fn cdata(self) -> Option> { + Some(*self.0) } fn sess(self) -> Option<&'tcx Session> { Some(&self.1) } } -impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'tcx>) { +impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, TyCtxt<'tcx>) { fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() } - fn cdata(self) -> Option<&'a CrateMetadata> { - Some(self.0) + fn cdata(self) -> Option> { + Some(*self.0) } fn tcx(self) -> Option> { Some(self.1) @@ -242,7 +242,7 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { self.tcx.expect("missing TyCtxt in DecodeContext") } - fn cdata(&self) -> &'a CrateMetadata { + fn cdata(&self) -> CrateMetadataRef<'a> { self.cdata.expect("missing CrateMetadata in DecodeContext") } @@ -364,7 +364,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { #[inline] fn specialized_decode(&mut self) -> Result { - self.specialized_decode().map(|i| LocalDefId::from_def_id(i)) + Ok(DefId::decode(self)?.expect_local()) } } @@ -386,7 +386,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { return Ok(DUMMY_SP); } - debug_assert_eq!(tag, TAG_VALID_SPAN); + debug_assert!(tag == TAG_VALID_SPAN_LOCAL || tag == TAG_VALID_SPAN_FOREIGN); let lo = BytePos::decode(self)?; let len = BytePos::decode(self)?; @@ -398,7 +398,68 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { bug!("Cannot decode Span without Session.") }; - let imported_source_files = self.cdata().imported_source_files(&sess.source_map()); + // There are two possibilities here: + // 1. This is a 'local span', which is located inside a `SourceFile` + // that came from this crate. In this case, we use the source map data + // encoded in this crate. This branch should be taken nearly all of the time. + // 2. This is a 'foreign span', which is located inside a `SourceFile` + // that came from a *different* crate (some crate upstream of the one + // whose metadata we're looking at). For example, consider this dependency graph: + // + // A -> B -> C + // + // Suppose that we're currently compiling crate A, and start deserializing + // metadata from crate B. When we deserialize a Span from crate B's metadata, + // there are two posibilites: + // + // 1. The span references a file from crate B. This makes it a 'local' span, + // which means that we can use crate B's serialized source map information. + // 2. The span references a file from crate C. This makes it a 'foreign' span, + // which means we need to use Crate *C* (not crate B) to determine the source + // map information. We only record source map information for a file in the + // crate that 'owns' it, so deserializing a Span may require us to look at + // a transitive dependency. + // + // When we encode a foreign span, we adjust its 'lo' and 'high' values + // to be based on the *foreign* crate (e.g. crate C), not the crate + // we are writing metadata for (e.g. crate B). This allows us to + // treat the 'local' and 'foreign' cases almost identically during deserialization: + // we can call `imported_source_files` for the proper crate, and binary search + // through the returned slice using our span. + let imported_source_files = if tag == TAG_VALID_SPAN_LOCAL { + self.cdata().imported_source_files(sess.source_map()) + } else { + // FIXME: We don't decode dependencies of proc-macros. + // Remove this once #69976 is merged + if self.cdata().root.is_proc_macro_crate() { + debug!( + "SpecializedDecoder::specialized_decode: skipping span for proc-macro crate {:?}", + self.cdata().cnum + ); + // Decode `CrateNum` as u32 - using `CrateNum::decode` will ICE + // since we don't have `cnum_map` populated. + // This advances the decoder position so that we can continue + // to read metadata. + let _ = u32::decode(self)?; + return Ok(DUMMY_SP); + } + // tag is TAG_VALID_SPAN_FOREIGN, checked by `debug_assert` above + let cnum = CrateNum::decode(self)?; + debug!( + "SpecializedDecoder::specialized_decode: loading source files from cnum {:?}", + cnum + ); + + // Decoding 'foreign' spans should be rare enough that it's + // not worth it to maintain a per-CrateNum cache for `last_source_file_index`. + // We just set it to 0, to ensure that we don't try to access something out + // of bounds for our initial 'guess' + self.last_source_file_index = 0; + + let foreign_data = self.cdata().cstore.get_crate_data(cnum); + foreign_data.imported_source_files(sess.source_map()) + }; + let source_file = { // Optimize for the case that most spans within a translated item // originate from the same source_file. @@ -408,28 +469,36 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { { last_source_file } else { - let mut a = 0; - let mut b = imported_source_files.len(); - - while b - a > 1 { - let m = (a + b) / 2; - if imported_source_files[m].original_start_pos > lo { - b = m; - } else { - a = m; - } + let index = imported_source_files + .binary_search_by_key(&lo, |source_file| source_file.original_start_pos) + .unwrap_or_else(|index| index - 1); + + // Don't try to cache the index for foreign spans, + // as this would require a map from CrateNums to indices + if tag == TAG_VALID_SPAN_LOCAL { + self.last_source_file_index = index; } - - self.last_source_file_index = a; - &imported_source_files[a] + &imported_source_files[index] } }; // Make sure our binary search above is correct. - debug_assert!(lo >= source_file.original_start_pos && lo <= source_file.original_end_pos); + debug_assert!( + lo >= source_file.original_start_pos && lo <= source_file.original_end_pos, + "Bad binary search: lo={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}", + lo, + source_file.original_start_pos, + source_file.original_end_pos + ); // Make sure we correctly filtered out invalid spans during encoding - debug_assert!(hi >= source_file.original_start_pos && hi <= source_file.original_end_pos); + debug_assert!( + hi >= source_file.original_start_pos && hi <= source_file.original_end_pos, + "Bad binary search: hi={:?} source_file.original_start_pos={:?} source_file.original_end_pos={:?}", + hi, + source_file.original_start_pos, + source_file.original_end_pos + ); let lo = (lo + source_file.translated_source_file.start_pos) - source_file.original_start_pos; @@ -500,7 +569,7 @@ impl MetadataBlob { } } -impl<'tcx> EntryKind<'tcx> { +impl EntryKind { fn def_kind(&self) -> Option { Some(match *self { EntryKind::Const(..) => DefKind::Const, @@ -512,7 +581,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Struct(_, _) => DefKind::Struct, EntryKind::Union(_, _) => DefKind::Union, EntryKind::Fn(_) | EntryKind::ForeignFn(_) => DefKind::Fn, - EntryKind::Method(_) => DefKind::Method, + EntryKind::AssocFn(_) => DefKind::AssocFn, EntryKind::Type => DefKind::TyAlias, EntryKind::TypeParam => DefKind::TyParam, EntryKind::ConstParam => DefKind::ConstParam, @@ -566,59 +635,16 @@ impl CrateRoot<'_> { } } -impl<'a, 'tcx> CrateMetadata { - crate fn new( - sess: &Session, - blob: MetadataBlob, - root: CrateRoot<'static>, - raw_proc_macros: Option<&'static [ProcMacro]>, - cnum: CrateNum, - cnum_map: CrateNumMap, - dep_kind: DepKind, - source: CrateSource, - private_dep: bool, - host_hash: Option, - ) -> CrateMetadata { - let def_path_table = record_time(&sess.perf_stats.decode_def_path_tables_time, || { - root.def_path_table.decode((&blob, sess)) - }); - let trait_impls = root - .impls - .decode((&blob, sess)) - .map(|trait_impls| (trait_impls.trait_id, trait_impls.impls)) - .collect(); - let alloc_decoding_state = - AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect()); - let dependencies = Lock::new(cnum_map.iter().cloned().collect()); - CrateMetadata { - blob, - root, - def_path_table, - trait_impls, - raw_proc_macros, - source_map_import_info: Once::new(), - alloc_decoding_state, - dep_node_index: AtomicCell::new(DepNodeIndex::INVALID), - cnum, - cnum_map, - dependencies, - dep_kind: Lock::new(dep_kind), - source, - private_dep, - host_hash, - extern_crate: Lock::new(None), - } - } - +impl<'a, 'tcx> CrateMetadataRef<'a> { fn is_proc_macro(&self, id: DefIndex) -> bool { self.root.proc_macro_data.and_then(|data| data.decode(self).find(|x| *x == id)).is_some() } - fn maybe_kind(&self, item_id: DefIndex) -> Option> { + fn maybe_kind(&self, item_id: DefIndex) -> Option { self.root.per_def.kind.get(self, item_id).map(|k| k.decode(self)) } - fn kind(&self, item_id: DefIndex) -> EntryKind<'tcx> { + fn kind(&self, item_id: DefIndex) -> EntryKind { assert!(!self.is_proc_macro(item_id)); self.maybe_kind(item_id).unwrap_or_else(|| { bug!( @@ -630,17 +656,9 @@ impl<'a, 'tcx> CrateMetadata { }) } - fn local_def_id(&self, index: DefIndex) -> DefId { - DefId { krate: self.cnum, index } - } - fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro { // DefIndex's in root.proc_macro_data have a one-to-one correspondence // with items in 'raw_proc_macros'. - // NOTE: If you update the order of macros in 'proc_macro_data' for any reason, - // you must also update src/librustc_builtin_macros/proc_macro_harness.rs - // Failing to do so will result in incorrect data being associated - // with proc macros when deserialized. let pos = self.root.proc_macro_data.unwrap().decode(self).position(|i| i == id).unwrap(); &self.raw_proc_macros.unwrap()[pos] } @@ -709,6 +727,7 @@ impl<'a, 'tcx> CrateMetadata { data.paren_sugar, data.has_auto_impl, data.is_marker, + data.specialization_kind, self.def_path_table.def_path_hash(item_id), ) } @@ -718,6 +737,7 @@ impl<'a, 'tcx> CrateMetadata { false, false, false, + ty::trait_def::TraitSpecializationKind::None, self.def_path_table.def_path_hash(item_id), ), _ => bug!("def-index does not refer to trait or trait alias"), @@ -727,7 +747,7 @@ impl<'a, 'tcx> CrateMetadata { fn get_variant( &self, tcx: TyCtxt<'tcx>, - kind: &EntryKind<'_>, + kind: &EntryKind, index: DefIndex, parent_did: DefId, ) -> ty::VariantDef { @@ -1125,7 +1145,7 @@ impl<'a, 'tcx> CrateMetadata { let (kind, container, has_self) = match self.kind(id) { EntryKind::AssocConst(container, _, _) => (ty::AssocKind::Const, container, false), - EntryKind::Method(data) => { + EntryKind::AssocFn(data) => { let data = data.decode(self); (ty::AssocKind::Method, data.container, data.has_self) } @@ -1203,18 +1223,6 @@ impl<'a, 'tcx> CrateMetadata { .collect() } - // Translate a DefId from the current compilation environment to a DefId - // for an external crate. - fn reverse_translate_def_id(&self, did: DefId) -> Option { - for (local, &global) in self.cnum_map.iter_enumerated() { - if global == did.krate { - return Some(DefId { krate: local, index: did.index }); - } - } - - None - } - fn get_inherent_implementations_for_type( &self, tcx: TyCtxt<'tcx>, @@ -1319,7 +1327,7 @@ impl<'a, 'tcx> CrateMetadata { fn get_fn_param_names(&self, id: DefIndex) -> Vec { let param_names = match self.kind(id) { EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).param_names, - EntryKind::Method(data) => data.decode(self).fn_data.param_names, + EntryKind::AssocFn(data) => data.decode(self).fn_data.param_names, _ => Lazy::empty(), }; param_names.decode(self).collect() @@ -1345,9 +1353,9 @@ impl<'a, 'tcx> CrateMetadata { } } - fn get_macro(&self, id: DefIndex) -> MacroDef { + fn get_macro(&self, id: DefIndex, sess: &Session) -> MacroDef { match self.kind(id) { - EntryKind::MacroDef(macro_def) => macro_def.decode(self), + EntryKind::MacroDef(macro_def) => macro_def.decode((self, sess)), _ => bug!(), } } @@ -1356,7 +1364,7 @@ impl<'a, 'tcx> CrateMetadata { // don't serialize constness for tuple variant and tuple struct constructors. fn is_const_fn_raw(&self, id: DefIndex) -> bool { let constness = match self.kind(id) { - EntryKind::Method(data) => data.decode(self).fn_data.constness, + EntryKind::AssocFn(data) => data.decode(self).fn_data.constness, EntryKind::Fn(data) => data.decode(self).constness, // Some intrinsics can be const fn. While we could recompute this (at least until we // stop having hardcoded whitelists and move to stability attributes), it seems cleaner @@ -1371,7 +1379,7 @@ impl<'a, 'tcx> CrateMetadata { fn asyncness(&self, id: DefIndex) -> hir::IsAsync { match self.kind(id) { EntryKind::Fn(data) => data.decode(self).asyncness, - EntryKind::Method(data) => data.decode(self).fn_data.asyncness, + EntryKind::AssocFn(data) => data.decode(self).fn_data.asyncness, EntryKind::ForeignFn(data) => data.decode(self).asyncness, _ => bug!("asyncness: expected function kind"), } @@ -1394,6 +1402,13 @@ impl<'a, 'tcx> CrateMetadata { } } + fn generator_kind(&self, id: DefIndex) -> Option { + match self.kind(id) { + EntryKind::Generator(data) => Some(data), + _ => None, + } + } + fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { self.root.per_def.fn_sig.get(self, id).unwrap().decode((self, tcx)) } @@ -1414,11 +1429,6 @@ impl<'a, 'tcx> CrateMetadata { DefPath::make(self.cnum, id, |parent| self.def_key(parent)) } - #[inline] - fn def_path_hash(&self, index: DefIndex) -> DefPathHash { - self.def_path_table.def_path_hash(index) - } - /// Imports the source_map from an external crate into the source_map of the crate /// currently being compiled (the "local crate"). /// @@ -1445,10 +1455,10 @@ impl<'a, 'tcx> CrateMetadata { /// Proc macro crates don't currently export spans, so this function does not have /// to work for them. fn imported_source_files( - &'a self, + &self, local_source_map: &source_map::SourceMap, - ) -> &[ImportedSourceFile] { - self.source_map_import_info.init_locking(|| { + ) -> &'a [ImportedSourceFile] { + self.cdata.source_map_import_info.init_locking(|| { let external_source_map = self.root.source_map.decode(self); external_source_map @@ -1492,19 +1502,21 @@ impl<'a, 'tcx> CrateMetadata { let local_version = local_source_map.new_imported_source_file( name, name_was_remapped, - self.cnum.as_u32(), src_hash, name_hash, source_length, + self.cnum, lines, multibyte_chars, non_narrow_chars, normalized_pos, + start_pos, + end_pos, ); debug!( "CrateMetaData::imported_source_files alloc \ - source_file {:?} original (start_pos {:?} end_pos {:?}) \ - translated (start_pos {:?} end_pos {:?})", + source_file {:?} original (start_pos {:?} end_pos {:?}) \ + translated (start_pos {:?} end_pos {:?})", local_version.name, start_pos, end_pos, @@ -1521,29 +1533,50 @@ impl<'a, 'tcx> CrateMetadata { .collect() }) } +} - /// Get the `DepNodeIndex` corresponding this crate. The result of this - /// method is cached in the `dep_node_index` field. - fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex { - let mut dep_node_index = self.dep_node_index.load(); - - if unlikely!(dep_node_index == DepNodeIndex::INVALID) { - // We have not cached the DepNodeIndex for this upstream crate yet, - // so use the dep-graph to find it out and cache it. - // Note that multiple threads can enter this block concurrently. - // That is fine because the DepNodeIndex remains constant - // throughout the whole compilation session, and multiple stores - // would always write the same value. - - let def_path_hash = self.def_path_hash(CRATE_DEF_INDEX); - let dep_node = def_path_hash.to_dep_node(dep_graph::DepKind::CrateMetadata); - - dep_node_index = tcx.dep_graph.dep_node_index_of(&dep_node); - assert!(dep_node_index != DepNodeIndex::INVALID); - self.dep_node_index.store(dep_node_index); +impl CrateMetadata { + crate fn new( + sess: &Session, + blob: MetadataBlob, + root: CrateRoot<'static>, + raw_proc_macros: Option<&'static [ProcMacro]>, + cnum: CrateNum, + cnum_map: CrateNumMap, + dep_kind: DepKind, + source: CrateSource, + private_dep: bool, + host_hash: Option, + ) -> CrateMetadata { + let def_path_table = record_time(&sess.perf_stats.decode_def_path_tables_time, || { + root.def_path_table.decode((&blob, sess)) + }); + let trait_impls = root + .impls + .decode((&blob, sess)) + .map(|trait_impls| (trait_impls.trait_id, trait_impls.impls)) + .collect(); + let alloc_decoding_state = + AllocDecodingState::new(root.interpret_alloc_index.decode(&blob).collect()); + let dependencies = Lock::new(cnum_map.iter().cloned().collect()); + CrateMetadata { + blob, + root, + def_path_table, + trait_impls, + raw_proc_macros, + source_map_import_info: Once::new(), + alloc_decoding_state, + dep_node_index: AtomicCell::new(DepNodeIndex::INVALID), + cnum, + cnum_map, + dependencies, + dep_kind: Lock::new(dep_kind), + source, + private_dep, + host_hash, + extern_crate: Lock::new(None), } - - dep_node_index } crate fn dependencies(&self) -> LockGuard<'_, Vec> { @@ -1618,10 +1651,56 @@ impl<'a, 'tcx> CrateMetadata { crate fn hash(&self) -> Svh { self.root.hash } + + fn local_def_id(&self, index: DefIndex) -> DefId { + DefId { krate: self.cnum, index } + } + + // Translate a DefId from the current compilation environment to a DefId + // for an external crate. + fn reverse_translate_def_id(&self, did: DefId) -> Option { + for (local, &global) in self.cnum_map.iter_enumerated() { + if global == did.krate { + return Some(DefId { krate: local, index: did.index }); + } + } + + None + } + + #[inline] + fn def_path_hash(&self, index: DefIndex) -> DefPathHash { + self.def_path_table.def_path_hash(index) + } + + /// Get the `DepNodeIndex` corresponding this crate. The result of this + /// method is cached in the `dep_node_index` field. + fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex { + let mut dep_node_index = self.dep_node_index.load(); + + if unlikely!(dep_node_index == DepNodeIndex::INVALID) { + // We have not cached the DepNodeIndex for this upstream crate yet, + // so use the dep-graph to find it out and cache it. + // Note that multiple threads can enter this block concurrently. + // That is fine because the DepNodeIndex remains constant + // throughout the whole compilation session, and multiple stores + // would always write the same value. + + let def_path_hash = self.def_path_hash(CRATE_DEF_INDEX); + let dep_node = + DepNode::from_def_path_hash(def_path_hash, dep_graph::DepKind::CrateMetadata); + + dep_node_index = tcx.dep_graph.dep_node_index_of(&dep_node); + assert!(dep_node_index != DepNodeIndex::INVALID); + self.dep_node_index.store(dep_node_index); + } + + dep_node_index + } } // Cannot be implemented on 'ProcMacro', as libproc_macro -// does not depend on libsyntax +// does not depend on librustc_ast fn macro_kind(raw: &ProcMacro) -> MacroKind { match raw { ProcMacro::CustomDerive { .. } => MacroKind::Derive, diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index fb7e5541e26..cc2bd51f92f 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -7,34 +7,27 @@ use crate::rmeta::{self, encoder}; use rustc::hir::exports::Export; use rustc::hir::map::definitions::DefPathTable; use rustc::hir::map::{DefKey, DefPath, DefPathHash}; -use rustc::middle::cstore::{CrateSource, CrateStore, DepKind, EncodedMetadata, NativeLibraryKind}; +use rustc::middle::cstore::{CrateSource, CrateStore, EncodedMetadata, NativeLibraryKind}; use rustc::middle::exported_symbols::ExportedSymbol; use rustc::middle::stability::DeprecationEntry; -use rustc::session::{CrateDisambiguator, Session}; use rustc::ty::query::Providers; use rustc::ty::query::QueryConfig; use rustc::ty::{self, TyCtxt}; +use rustc_ast::ast; +use rustc_ast::attr; +use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_parse::parser::emit_unclosed_delims; -use rustc_parse::source_file_to_stream; +use rustc_session::{CrateDisambiguator, Session}; +use rustc_span::source_map::{self, Span, Spanned}; +use rustc_span::symbol::Symbol; use rustc_data_structures::sync::Lrc; use smallvec::SmallVec; use std::any::Any; use std::sync::Arc; -use rustc_span::source_map; -use rustc_span::source_map::Spanned; -use rustc_span::symbol::Symbol; -use rustc_span::{FileName, Span}; -use syntax::ast; -use syntax::attr; -use syntax::expand::allocator::AllocatorKind; -use syntax::ptr::P; -use syntax::tokenstream::DelimSpan; - macro_rules! provide { (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $($name:ident => $compute:block)*) => { @@ -134,6 +127,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, asyncness => { cdata.asyncness(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } static_mutability => { cdata.static_mutability(def_id.index) } + generator_kind => { cdata.generator_kind(def_id.index) } def_kind => { cdata.def_kind(def_id.index) } def_span => { cdata.get_span(def_id.index, &tcx.sess) } lookup_stability => { @@ -146,7 +140,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, cdata.get_deprecation(def_id.index).map(DeprecationEntry::external) } item_attrs => { cdata.get_item_attrs(def_id.index, tcx.sess) } - // FIXME(#38501) We've skipped a `read` on the `HirBody` of + // FIXME(#38501) We've skipped a `read` on the `hir_owner_items` of // a `fn` when encoding, so the dep-tracking wouldn't work. // This is only used by rustdoc anyway, which shouldn't have // incremental recompilation ever enabled. @@ -392,14 +386,6 @@ pub fn provide(providers: &mut Providers<'_>) { } impl CStore { - pub fn export_macros_untracked(&self, cnum: CrateNum) { - let data = self.get_crate_data(cnum); - let mut dep_kind = data.dep_kind.lock(); - if *dep_kind == DepKind::UnexportedMacrosOnly { - *dep_kind = DepKind::MacrosOnly; - } - } - pub fn struct_field_names_untracked(&self, def: DefId, sess: &Session) -> Vec> { self.get_crate_data(def.krate).get_struct_field_names(def.index, sess) } @@ -426,15 +412,7 @@ impl CStore { return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, sess)); } - let def = data.get_macro(id.index); - let macro_full_name = data.def_path(id.index).to_string_friendly(|_| data.root.name); - let source_name = FileName::Macros(macro_full_name); - - let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body); - let local_span = Span::with_root_ctxt(source_file.start_pos, source_file.end_pos); - let dspan = DelimSpan::from_single(local_span); - let (body, mut errors) = source_file_to_stream(&sess.parse_sess, source_file, None); - emit_unclosed_delims(&mut errors, &sess.parse_sess); + let span = data.get_span(id.index, sess); // Mark the attrs as used let attrs = data.get_item_attrs(id.index, sess); @@ -442,28 +420,22 @@ impl CStore { attr::mark_used(attr); } - let name = data + let ident = data .def_key(id.index) .disambiguated_data .data .get_opt_name() + .map(ast::Ident::with_dummy_span) // FIXME: cross-crate hygiene .expect("no name in load_macro"); - sess.imported_macro_spans - .borrow_mut() - .insert(local_span, (name.to_string(), data.get_span(id.index, sess))); LoadedMacro::MacroDef( ast::Item { - // FIXME: cross-crate hygiene - ident: ast::Ident::with_dummy_span(name), + ident, id: ast::DUMMY_NODE_ID, - span: local_span, + span, attrs: attrs.iter().cloned().collect(), - kind: ast::ItemKind::MacroDef(ast::MacroDef { - body: P(ast::MacArgs::Delimited(dspan, ast::MacDelimiter::Brace, body)), - legacy: def.legacy, - }), - vis: source_map::respan(local_span.shrink_to_lo(), ast::VisibilityKind::Inherited), + kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)), + vis: source_map::respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), tokens: None, }, data.root.edition, @@ -524,7 +496,7 @@ impl CrateStore for CStore { } fn def_path_table(&self, cnum: CrateNum) -> &DefPathTable { - &self.get_crate_data(cnum).def_path_table + &self.get_crate_data(cnum).cdata.def_path_table } fn crates_untracked(&self) -> Vec { diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index 4133047af78..6280fd62de9 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -1,6 +1,7 @@ use crate::rmeta::table::FixedSizeEncoding; use crate::rmeta::*; +use log::{debug, trace}; use rustc::hir::map::definitions::DefPathTable; use rustc::hir::map::Map; use rustc::middle::cstore::{EncodedMetadata, ForeignModule, LinkagePreference, NativeLibrary}; @@ -12,33 +13,28 @@ use rustc::traits::specialization_graph; use rustc::ty::codec::{self as ty_codec, TyEncoder}; use rustc::ty::layout::VariantIdx; use rustc::ty::{self, SymbolName, Ty, TyCtxt}; +use rustc_ast::ast; +use rustc_ast::attr; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::StableHasher; +use rustc_data_structures::sync::Lrc; +use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{AnonConst, GenericParamKind}; use rustc_index::vec::Idx; - -use rustc::session::config::{self, CrateType}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::StableHasher; -use rustc_data_structures::sync::Lrc; use rustc_serialize::{opaque, Encodable, Encoder, SpecializedEncoder}; - -use log::{debug, trace}; +use rustc_session::config::{self, CrateType}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{self, FileName, SourceFile, Span}; +use rustc_span::{self, ExternalSource, FileName, SourceFile, Span}; use std::hash::Hash; use std::num::NonZeroUsize; use std::path::Path; use std::u32; -use syntax::ast; -use syntax::attr; -use syntax::expand::is_proc_macro_attr; - -use rustc_hir as hir; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; struct EncodeContext<'tcx> { opaque: opaque::Encoder, @@ -168,20 +164,56 @@ impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { return TAG_INVALID_SPAN.encode(self); } - // HACK(eddyb) there's no way to indicate which crate a Span is coming - // from right now, so decoding would fail to find the SourceFile if - // it's not local to the crate the Span is found in. - if self.source_file_cache.is_imported() { - return TAG_INVALID_SPAN.encode(self); - } + // There are two possible cases here: + // 1. This span comes from a 'foreign' crate - e.g. some crate upstream of the + // crate we are writing metadata for. When the metadata for *this* crate gets + // deserialized, the deserializer will need to know which crate it originally came + // from. We use `TAG_VALID_SPAN_FOREIGN` to indicate that a `CrateNum` should + // be deserialized after the rest of the span data, which tells the deserializer + // which crate contains the source map information. + // 2. This span comes from our own crate. No special hamdling is needed - we just + // write `TAG_VALID_SPAN_LOCAL` to let the deserializer know that it should use + // our own source map information. + let (tag, lo, hi) = if self.source_file_cache.is_imported() { + // To simplify deserialization, we 'rebase' this span onto the crate it originally came from + // (the crate that 'owns' the file it references. These rebased 'lo' and 'hi' values + // are relative to the source map information for the 'foreign' crate whose CrateNum + // we write into the metadata. This allows `imported_source_files` to binary + // search through the 'foreign' crate's source map information, using the + // deserialized 'lo' and 'hi' values directly. + // + // All of this logic ensures that the final result of deserialization is a 'normal' + // Span that can be used without any additional trouble. + let external_start_pos = { + // Introduce a new scope so that we drop the 'lock()' temporary + match &*self.source_file_cache.external_src.lock() { + ExternalSource::Foreign { original_start_pos, .. } => *original_start_pos, + src => panic!("Unexpected external source {:?}", src), + } + }; + let lo = (span.lo - self.source_file_cache.start_pos) + external_start_pos; + let hi = (span.hi - self.source_file_cache.start_pos) + external_start_pos; + + (TAG_VALID_SPAN_FOREIGN, lo, hi) + } else { + (TAG_VALID_SPAN_LOCAL, span.lo, span.hi) + }; - TAG_VALID_SPAN.encode(self)?; - span.lo.encode(self)?; + tag.encode(self)?; + lo.encode(self)?; // Encode length which is usually less than span.hi and profits more // from the variable-length integer encoding that we use. - let len = span.hi - span.lo; - len.encode(self) + let len = hi - lo; + len.encode(self)?; + + if tag == TAG_VALID_SPAN_FOREIGN { + // This needs to be two lines to avoid holding the `self.source_file_cache` + // while calling `cnum.encode(self)` + let cnum = self.source_file_cache.cnum; + cnum.encode(self)?; + } + Ok(()) // Don't encode the expansion context. } @@ -307,7 +339,7 @@ impl<'tcx> EncodeContext<'tcx> { assert!( last_min_end <= lazy.position, "make sure that the calls to `lazy*` \ - are in the same order as the metadata fields", + are in the same order as the metadata fields", ); lazy.position.get() - last_min_end.get() } @@ -332,7 +364,7 @@ impl<'tcx> EncodeContext<'tcx> { fn encode_info_for_items(&mut self) { let krate = self.tcx.hir().krate(); let vis = Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public }; - self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.module, &krate.attrs, &vis); + self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module, &krate.item.attrs, &vis); krate.visit_all_item_likes(&mut self.as_deep_visitor()); for macro_def in krate.exported_macros { self.visit_macro_def(macro_def); @@ -494,7 +526,7 @@ impl<'tcx> EncodeContext<'tcx> { edition: tcx.sess.edition(), has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE), has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), - has_default_lib_allocator: has_default_lib_allocator, + has_default_lib_allocator, plugin_registrar_fn: tcx.plugin_registrar_fn(LOCAL_CRATE).map(|id| id.index), proc_macro_decls_static: if is_proc_macro { let id = tcx.proc_macro_decls_static(LOCAL_CRATE).unwrap(); @@ -504,7 +536,7 @@ impl<'tcx> EncodeContext<'tcx> { }, proc_macro_data, proc_macro_stability: if is_proc_macro { - tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).map(|stab| *stab) + tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied() } else { None }, @@ -806,12 +838,12 @@ impl EncodeContext<'tcx> { ) } ty::AssocKind::Method => { - let fn_data = if let hir::TraitItemKind::Method(m_sig, m) = &ast_item.kind { + let fn_data = if let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind { let param_names = match *m { - hir::TraitMethod::Required(ref names) => { + hir::TraitFn::Required(ref names) => { self.encode_fn_param_names(names) } - hir::TraitMethod::Provided(body) => { + hir::TraitFn::Provided(body) => { self.encode_fn_param_names_for_body(body) } }; @@ -823,7 +855,7 @@ impl EncodeContext<'tcx> { } else { bug!() }; - EntryKind::Method(self.lazy(MethodData { + EntryKind::AssocFn(self.lazy(AssocFnData { fn_data, container, has_self: trait_item.method_has_self_argument, @@ -895,7 +927,7 @@ impl EncodeContext<'tcx> { } } ty::AssocKind::Method => { - let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.kind { + let fn_data = if let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind { FnData { asyncness: sig.header.asyncness, constness: sig.header.constness, @@ -904,7 +936,7 @@ impl EncodeContext<'tcx> { } else { bug!() }; - EntryKind::Method(self.lazy(MethodData { + EntryKind::AssocFn(self.lazy(AssocFnData { fn_data, container, has_self: impl_item.method_has_self_argument, @@ -929,7 +961,7 @@ impl EncodeContext<'tcx> { self.encode_inferred_outlives(def_id); let mir = match ast_item.kind { hir::ImplItemKind::Const(..) => true, - hir::ImplItemKind::Method(ref sig, _) => { + hir::ImplItemKind::Fn(ref sig, _) => { let generics = self.tcx.generics_of(def_id); let needs_inline = (generics.requires_monomorphization(self.tcx) || tcx.codegen_fn_attrs(def_id).requests_inline()) @@ -1078,12 +1110,13 @@ impl EncodeContext<'tcx> { let polarity = self.tcx.impl_polarity(def_id); let parent = if let Some(trait_ref) = trait_ref { let trait_def = self.tcx.trait_def(trait_ref.def_id); - trait_def.ancestors(self.tcx, def_id).nth(1).and_then(|node| { - match node { - specialization_graph::Node::Impl(parent) => Some(parent), - _ => None, - } - }) + trait_def.ancestors(self.tcx, def_id).ok() + .and_then(|mut an| an.nth(1).and_then(|node| { + match node { + specialization_graph::Node::Impl(parent) => Some(parent), + _ => None, + } + })) } else { None }; @@ -1115,6 +1148,7 @@ impl EncodeContext<'tcx> { paren_sugar: trait_def.paren_sugar, has_auto_impl: self.tcx.trait_is_auto(def_id), is_marker: trait_def.is_marker, + specialization_kind: trait_def.specialization_kind, }; EntryKind::Trait(self.lazy(data)) @@ -1236,12 +1270,8 @@ impl EncodeContext<'tcx> { /// Serialize the text of exported macros fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef<'_>) { - use rustc_ast_pretty::pprust; let def_id = self.tcx.hir().local_def_id(macro_def.hir_id); - record!(self.per_def.kind[def_id] <- EntryKind::MacroDef(self.lazy(MacroDef { - body: pprust::tts_to_string(macro_def.body.clone()), - legacy: macro_def.legacy, - }))); + record!(self.per_def.kind[def_id] <- EntryKind::MacroDef(self.lazy(macro_def.ast.clone()))); record!(self.per_def.visibility[def_id] <- ty::Visibility::Public); record!(self.per_def.span[def_id] <- macro_def.span); record!(self.per_def.attributes[def_id] <- macro_def.attrs); @@ -1249,12 +1279,7 @@ impl EncodeContext<'tcx> { self.encode_deprecation(def_id); } - fn encode_info_for_generic_param( - &mut self, - def_id: DefId, - kind: EntryKind<'tcx>, - encode_type: bool, - ) { + fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) { record!(self.per_def.kind[def_id] <- kind); record!(self.per_def.visibility[def_id] <- ty::Visibility::Public); record!(self.per_def.span[def_id] <- self.tcx.def_span(def_id)); @@ -1272,12 +1297,9 @@ impl EncodeContext<'tcx> { let ty = self.tcx.typeck_tables_of(def_id).node_type(hir_id); record!(self.per_def.kind[def_id] <- match ty.kind { - ty::Generator(def_id, ..) => { - let layout = self.tcx.generator_layout(def_id); - let data = GeneratorData { - layout: layout.clone(), - }; - EntryKind::Generator(self.lazy(data)) + ty::Generator(..) => { + let data = self.tcx.generator_kind(def_id).unwrap(); + EntryKind::Generator(data) } ty::Closure(..) => EntryKind::Closure, @@ -1328,13 +1350,7 @@ impl EncodeContext<'tcx> { let is_proc_macro = self.tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro); if is_proc_macro { let tcx = self.tcx; - Some(self.lazy(tcx.hir().krate().items.values().filter_map(|item| { - if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) { - Some(item.hir_id.owner) - } else { - None - } - }))) + Some(self.lazy(tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index))) } else { None } @@ -1422,8 +1438,8 @@ impl EncodeContext<'tcx> { .into_iter() .map(|(trait_def_id, mut impls)| { // Bring everything into deterministic order for hashing - impls.sort_by_cached_key(|&def_index| { - tcx.hir().definitions().def_path_hash(def_index) + impls.sort_by_cached_key(|&index| { + tcx.hir().definitions().def_path_hash(LocalDefId { local_def_index: index }) }); TraitImpls { @@ -1521,8 +1537,8 @@ impl EncodeContext<'tcx> { impl Visitor<'tcx> for EncodeContext<'tcx> { type Map = Map<'tcx>; - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir()) + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.tcx.hir()) } fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { intravisit::walk_expr(self, ex); diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index 77ec3eb4555..05d834e5dee 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -7,9 +7,8 @@ use rustc::middle::cstore::{DepKind, ForeignModule, LinkagePreference, NativeLib use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::middle::lang_items; use rustc::mir; -use rustc::session::config::SymbolManglingVersion; -use rustc::session::CrateDisambiguator; use rustc::ty::{self, ReprOptions, Ty}; +use rustc_ast::ast::{self, MacroDef}; use rustc_attr as attr; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; @@ -18,11 +17,12 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, DefIndex}; use rustc_index::vec::IndexVec; use rustc_serialize::opaque::Encoder; +use rustc_session::config::SymbolManglingVersion; +use rustc_session::CrateDisambiguator; use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; use rustc_span::{self, Span}; use rustc_target::spec::{PanicStrategy, TargetTriple}; -use syntax::ast; use std::marker::PhantomData; use std::num::NonZeroUsize; @@ -201,7 +201,7 @@ crate struct CrateRoot<'tcx> { per_def: LazyPerDefTables<'tcx>, - /// The DefIndex's of any proc macros delcared by this crate. + /// The DefIndex's of any proc macros declared by this crate. proc_macro_data: Option>, compiler_builtins: bool, @@ -252,7 +252,7 @@ macro_rules! define_per_def_tables { } define_per_def_tables! { - kind: Table)>, + kind: Table>, visibility: Table>, span: Table>, attributes: Table>, @@ -279,7 +279,7 @@ define_per_def_tables! { } #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -enum EntryKind<'tcx> { +enum EntryKind { Const(mir::ConstQualifs, Lazy), ImmStatic, MutStatic, @@ -302,10 +302,10 @@ enum EntryKind<'tcx> { Mod(Lazy), MacroDef(Lazy), Closure, - Generator(Lazy!(GeneratorData<'tcx>)), + Generator(hir::GeneratorKind), Trait(Lazy), Impl(Lazy), - Method(Lazy), + AssocFn(Lazy), AssocType(AssocContainer), AssocOpaqueTy(AssocContainer), AssocConst(AssocContainer, mir::ConstQualifs, Lazy), @@ -322,12 +322,6 @@ struct ModData { reexports: Lazy<[Export]>, } -#[derive(RustcEncodable, RustcDecodable)] -struct MacroDef { - body: String, - legacy: bool, -} - #[derive(RustcEncodable, RustcDecodable)] struct FnData { asyncness: hir::IsAsync, @@ -349,6 +343,7 @@ struct TraitData { paren_sugar: bool, has_auto_impl: bool, is_marker: bool, + specialization_kind: ty::trait_def::TraitSpecializationKind, } #[derive(RustcEncodable, RustcDecodable)] @@ -398,7 +393,7 @@ impl AssocContainer { } #[derive(RustcEncodable, RustcDecodable)] -struct MethodData { +struct AssocFnData { fn_data: FnData, container: AssocContainer, has_self: bool, @@ -410,5 +405,6 @@ struct GeneratorData<'tcx> { } // Tags used for encoding Spans: -const TAG_VALID_SPAN: u8 = 0; -const TAG_INVALID_SPAN: u8 = 1; +const TAG_VALID_SPAN_LOCAL: u8 = 0; +const TAG_VALID_SPAN_FOREIGN: u8 = 1; +const TAG_INVALID_SPAN: u8 = 2; diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 6b2e2bb919c..256a80076b9 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -15,7 +15,7 @@ dot = { path = "../libgraphviz", package = "graphviz" } itertools = "0.8" log = "0.4" log_settings = "0.1.1" -polonius-engine = "0.11.0" +polonius-engine = "0.12.0" rustc = { path = "../librustc" } rustc_ast_pretty = { path = "../librustc_ast_pretty" } rustc_attr = { path = "../librustc_attr" } @@ -23,11 +23,14 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } rustc_index = { path = "../librustc_index" } +rustc_infer = { path = "../librustc_infer" } rustc_lexer = { path = "../librustc_lexer" } rustc_macros = { path = "../librustc_macros" } rustc_serialize = { path = "../libserialize", package = "serialize" } +rustc_session = { path = "../librustc_session" } rustc_target = { path = "../librustc_target" } -syntax = { path = "../libsyntax" } +rustc_trait_selection = { path = "../librustc_trait_selection" } +rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } rustc_apfloat = { path = "../librustc_apfloat" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_mir/borrow_check/constraint_generation.rs b/src/librustc_mir/borrow_check/constraint_generation.rs index 19b7e0cf59b..46cfe0897a9 100644 --- a/src/librustc_mir/borrow_check/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/constraint_generation.rs @@ -1,4 +1,3 @@ -use rustc::infer::InferCtxt; use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; use rustc::mir::{ @@ -8,6 +7,7 @@ use rustc::mir::{ use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, RegionVid, Ty}; +use rustc_infer::infer::InferCtxt; use crate::borrow_check::{ borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, nll::ToRegionVid, diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index c7c7db9ad80..e895eec5d52 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -3,7 +3,6 @@ use rustc::mir::{ FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, }; -use rustc::traits::error_reporting::suggest_constraining_type_param; use rustc::ty::{self, Ty}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder}; @@ -13,6 +12,7 @@ use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; use rustc_index::vec::Idx; use rustc_span::source_map::DesugaringKind; use rustc_span::Span; +use rustc_trait_selection::traits::error_reporting::suggest_constraining_type_param; use crate::dataflow::drop_flag_effects; use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex}; @@ -51,7 +51,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, location: Location, desired_action: InitializationRequiringAction, - (moved_place, used_place, span): (PlaceRef<'cx, 'tcx>, PlaceRef<'cx, 'tcx>, Span), + (moved_place, used_place, span): (PlaceRef<'tcx>, PlaceRef<'tcx>, Span), mpi: MovePathIndex, ) { debug!( @@ -647,7 +647,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // borrowed place and look for a access to a different field of the same union. let Place { local, projection } = second_borrowed_place; - let mut cursor = projection.as_ref(); + let mut cursor = &projection[..]; while let [proj_base @ .., elem] = cursor { cursor = proj_base; @@ -1231,7 +1231,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { GeneratorKind::Async(async_kind) => match async_kind { AsyncGeneratorKind::Block => "async block", AsyncGeneratorKind::Closure => "async closure", - _ => bug!("async block/closure expected, but async funtion found."), + _ => bug!("async block/closure expected, but async function found."), }, GeneratorKind::Gen => "generator", }, @@ -1257,7 +1257,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } _ => bug!( "report_escaping_closure_capture called with unexpected constraint \ - category: `{:?}`", + category: `{:?}`", category ), }; @@ -1275,17 +1275,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> DiagnosticBuilder<'cx> { let tcx = self.infcx.tcx; - let escapes_from = if tcx.is_closure(self.mir_def_id) { - let tables = tcx.typeck_tables_of(self.mir_def_id); - let mir_hir_id = tcx.hir().def_index_to_hir_id(self.mir_def_id.index); - match tables.node_type(mir_hir_id).kind { - ty::Closure(..) => "closure", - ty::Generator(..) => "generator", - _ => bug!("Closure body doesn't have a closure or generator type"), - } - } else { - "function" - }; + let (_, escapes_from) = tcx.article_and_description(self.mir_def_id); let mut err = borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from); @@ -1350,7 +1340,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // there. let mut mpis = vec![mpi]; let move_paths = &self.move_data.move_paths; - mpis.extend(move_paths[mpi].parents(move_paths)); + mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi)); for moi in &self.move_data.loc_map[location] { debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi); @@ -1531,7 +1521,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.buffer(&mut self.errors_buffer); } - fn classify_drop_access_kind(&self, place: PlaceRef<'cx, 'tcx>) -> StorageDeadOrDrop<'tcx> { + fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> { let tcx = self.infcx.tcx; match place.projection { [] => StorageDeadOrDrop::LocalStorageDead, @@ -1885,7 +1875,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // as the HIR doesn't have full types for closure arguments. let return_ty = *sig.output().skip_binder(); let mut return_span = fn_decl.output.span(); - if let hir::FunctionRetTy::Return(ty) = &fn_decl.output { + if let hir::FnRetTy::Return(ty) = &fn_decl.output { if let hir::TyKind::Rptr(lifetime, _) = ty.kind { return_span = lifetime.span; } diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs index 01b7c5645fe..6475677988f 100644 --- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs +++ b/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs @@ -2,7 +2,6 @@ use std::collections::VecDeque; -use rustc::infer::NLLRegionVariableOrigin; use rustc::mir::{ Body, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind, @@ -12,6 +11,7 @@ use rustc::ty::{self, RegionVid, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_index::vec::IndexVec; +use rustc_infer::infer::NLLRegionVariableOrigin; use rustc_span::symbol::Symbol; use rustc_span::Span; diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs index ba4af59eede..7110a4a3058 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs @@ -51,7 +51,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { pub(super) fn add_moved_or_invoked_closure_note( &self, location: Location, - place: PlaceRef<'cx, 'tcx>, + place: PlaceRef<'tcx>, diag: &mut DiagnosticBuilder<'_>, ) { debug!("add_moved_or_invoked_closure_note: location={:?} place={:?}", location, place); @@ -139,7 +139,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// End-user visible description of `place` if one can be found. If the /// place is a temporary for instance, None will be returned. - pub(super) fn describe_place(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Option { + pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option { self.describe_place_with_options(place_ref, IncludingDowncast(false)) } @@ -149,7 +149,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// `Downcast` and `IncludingDowncast` is true pub(super) fn describe_place_with_options( &self, - place: PlaceRef<'cx, 'tcx>, + place: PlaceRef<'tcx>, including_downcast: IncludingDowncast, ) -> Option { let mut buf = String::new(); @@ -162,7 +162,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Appends end-user visible description of `place` to `buf`. fn append_place_to_string( &self, - place: PlaceRef<'cx, 'tcx>, + place: PlaceRef<'tcx>, buf: &mut String, mut autoderef: bool, including_downcast: &IncludingDowncast, @@ -175,7 +175,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.body.local_decls[local].is_ref_for_guard() => { self.append_place_to_string( - PlaceRef { local: local, projection: &[] }, + PlaceRef { local, projection: &[] }, buf, autoderef, &including_downcast, @@ -303,7 +303,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } /// End-user visible description of the `field`nth field of `base` - fn describe_field(&self, place: PlaceRef<'cx, 'tcx>, field: Field) -> String { + fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String { // FIXME Place2 Make this work iteratively match place { PlaceRef { local, projection: [] } => { @@ -399,7 +399,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { pub(super) fn borrowed_content_source( &self, - deref_base: PlaceRef<'cx, 'tcx>, + deref_base: PlaceRef<'tcx>, ) -> BorrowedContentSource<'tcx> { let tcx = self.infcx.tcx; @@ -619,14 +619,14 @@ pub(super) enum BorrowedContentSource<'tcx> { impl BorrowedContentSource<'tcx> { pub(super) fn describe_for_unnamed_place(&self) -> String { match *self { - BorrowedContentSource::DerefRawPointer => format!("a raw pointer"), - BorrowedContentSource::DerefSharedRef => format!("a shared reference"), - BorrowedContentSource::DerefMutableRef => format!("a mutable reference"), + BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(), + BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(), + BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(), BorrowedContentSource::OverloadedDeref(ty) => { if ty.is_rc() { - format!("an `Rc`") + "an `Rc`".to_string() } else if ty.is_arc() { - format!("an `Arc`") + "an `Arc`".to_string() } else { format!("dereference of `{}`", ty) } @@ -649,16 +649,16 @@ impl BorrowedContentSource<'tcx> { pub(super) fn describe_for_immutable_place(&self) -> String { match *self { - BorrowedContentSource::DerefRawPointer => format!("a `*const` pointer"), - BorrowedContentSource::DerefSharedRef => format!("a `&` reference"), + BorrowedContentSource::DerefRawPointer => "a `*const` pointer".to_string(), + BorrowedContentSource::DerefSharedRef => "a `&` reference".to_string(), BorrowedContentSource::DerefMutableRef => { bug!("describe_for_immutable_place: DerefMutableRef isn't immutable") } BorrowedContentSource::OverloadedDeref(ty) => { if ty.is_rc() { - format!("an `Rc`") + "an `Rc`".to_string() } else if ty.is_arc() { - format!("an `Arc`") + "an `Arc`".to_string() } else { format!("a dereference of `{}`", ty) } @@ -694,7 +694,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Finds the spans associated to a move or copy of move_place at location. pub(super) fn move_spans( &self, - moved_place: PlaceRef<'cx, 'tcx>, // Could also be an upvar. + moved_place: PlaceRef<'tcx>, // Could also be an upvar. location: Location, ) -> UseSpans { use self::UseSpans::*; @@ -782,7 +782,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn closure_span( &self, def_id: DefId, - target_place: PlaceRef<'cx, 'tcx>, + target_place: PlaceRef<'tcx>, places: &Vec>, ) -> Option<(Span, Option, Span)> { debug!( diff --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs index 14f675c0fdf..9451fee499d 100644 --- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/move_errors.rs @@ -443,7 +443,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let place_ty = move_from.ty(*self.body, self.infcx.tcx).ty; let place_desc = match self.describe_place(move_from.as_ref()) { Some(desc) => format!("`{}`", desc), - None => format!("value"), + None => "value".to_string(), }; self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span)); @@ -466,7 +466,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let place_ty = original_path.ty(*self.body, self.infcx.tcx).ty; let place_desc = match self.describe_place(original_path.as_ref()) { Some(desc) => format!("`{}`", desc), - None => format!("value"), + None => "value".to_string(), }; self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span)); @@ -519,7 +519,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } fn add_move_error_details(&self, err: &mut DiagnosticBuilder<'a>, binds_to: &[Local]) { - for (j, local) in binds_to.into_iter().enumerate() { + for (j, local) in binds_to.iter().enumerate() { let bind_to = &self.body.local_decls[*local]; let binding_span = bind_to.source_info.span; diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs index d91f6edc980..c462f934148 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs @@ -23,7 +23,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &mut self, access_place: &Place<'tcx>, span: Span, - the_place_err: PlaceRef<'cx, 'tcx>, + the_place_err: PlaceRef<'tcx>, error_access: AccessKind, location: Location, ) { @@ -329,40 +329,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if self.body.local_decls[local].is_user_variable() => { let local_decl = &self.body.local_decls[local]; - let suggestion = match local_decl.local_info { - LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(_))) => { - Some(suggest_ampmut_self(self.infcx.tcx, local_decl)) - } - - LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( - mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), - opt_ty_info, - .. - }, - ))) => Some(suggest_ampmut( - self.infcx.tcx, - self.body, - local, - local_decl, - opt_ty_info, - )), - - LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( - mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByReference(_), - .. - }, - ))) => { - let pattern_span = local_decl.source_info.span; - suggest_ref_mut(self.infcx.tcx, pattern_span) - .map(|replacement| (pattern_span, replacement)) - } - - LocalInfo::User(ClearCrossCrate::Clear) => bug!("saw cleared local state"), - - _ => unreachable!(), - }; let (pointer_sigil, pointer_desc) = if local_decl.ty.is_region_ptr() { ("&", "reference") @@ -370,17 +336,53 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ("*const", "pointer") }; - if let Some((err_help_span, suggested_code)) = suggestion { - err.span_suggestion( - err_help_span, - &format!("consider changing this to be a mutable {}", pointer_desc), - suggested_code, - Applicability::MachineApplicable, - ); - } - match self.local_names[local] { Some(name) if !local_decl.from_compiler_desugaring() => { + let suggestion = match local_decl.local_info { + LocalInfo::User(ClearCrossCrate::Set( + mir::BindingForm::ImplicitSelf(_), + )) => Some(suggest_ampmut_self(self.infcx.tcx, local_decl)), + + LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(_), + opt_ty_info, + .. + }, + ))) => Some(suggest_ampmut( + self.infcx.tcx, + self.body, + local, + local_decl, + opt_ty_info, + )), + + LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByReference(_), + .. + }, + ))) => { + let pattern_span = local_decl.source_info.span; + suggest_ref_mut(self.infcx.tcx, pattern_span) + .map(|replacement| (pattern_span, replacement)) + } + + LocalInfo::User(ClearCrossCrate::Clear) => { + bug!("saw cleared local state") + } + + _ => unreachable!(), + }; + + if let Some((err_help_span, suggested_code)) = suggestion { + err.span_suggestion( + err_help_span, + &format!("consider changing this to be a mutable {}", pointer_desc), + suggested_code, + Applicability::MachineApplicable, + ); + } err.span_label( span, format!( @@ -445,7 +447,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.buffer(&mut self.errors_buffer); } - /// Targetted error when encountering an `FnMut` closure where an `Fn` closure was expected. + /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected. fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) { err.span_label(sp, format!("cannot {}", act)); @@ -478,12 +480,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { })) | Some(hir::Node::TraitItem(hir::TraitItem { ident, - kind: hir::TraitItemKind::Method(sig, _), + kind: hir::TraitItemKind::Fn(sig, _), .. })) | Some(hir::Node::ImplItem(hir::ImplItem { ident, - kind: hir::ImplItemKind::Method(sig, _), + kind: hir::ImplItemKind::Fn(sig, _), .. })) => Some( arg_pos @@ -520,12 +522,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. }) | hir::Node::TraitItem(hir::TraitItem { ident, - kind: hir::TraitItemKind::Method(sig, _), + kind: hir::TraitItemKind::Fn(sig, _), .. }) | hir::Node::ImplItem(hir::ImplItem { ident, - kind: hir::ImplItemKind::Method(sig, _), + kind: hir::ImplItemKind::Fn(sig, _), .. }) => { err.span_label(ident.span, ""); diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index 0e040ec7827..494b6421fd5 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -1,12 +1,12 @@ //! Error reporting machinery for lifetime errors. -use rustc::infer::{ - error_reporting::nice_region_error::NiceRegionError, opaque_types, NLLRegionVariableOrigin, -}; use rustc::mir::ConstraintCategory; use rustc::ty::{self, RegionVid, Ty}; use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_hir::def_id::DefId; +use rustc_infer::infer::{ + error_reporting::nice_region_error::NiceRegionError, + error_reporting::unexpected_hidden_region_diagnostic, NLLRegionVariableOrigin, +}; use rustc_span::symbol::kw; use rustc_span::Span; @@ -58,8 +58,8 @@ crate enum RegionErrorKind<'tcx> { /// An unexpected hidden region for an opaque type. UnexpectedHiddenRegion { - /// The def id of the opaque type. - opaque_type_def_id: DefId, + /// The span for the member constraint. + span: Span, /// The hidden type. hidden_ty: Ty<'tcx>, /// The unexpected region. @@ -194,18 +194,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - RegionErrorKind::UnexpectedHiddenRegion { - opaque_type_def_id, - hidden_ty, - member_region, - } => { + RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => { let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id); - opaque_types::unexpected_hidden_region_diagnostic( + let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty); + let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region); + unexpected_hidden_region_diagnostic( self.infcx.tcx, Some(region_scope_tree), - opaque_type_def_id, - hidden_ty, - member_region, + span, + named_ty, + named_region, ) .buffer(&mut self.errors_buffer); } @@ -286,8 +284,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { debug!("report_region_error: category={:?} {:?}", category, span); // Check if we can use one of the "nice region errors". if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { - let tables = self.infcx.tcx.typeck_tables_of(self.mir_def_id); - let nice = NiceRegionError::new_from_span(self.infcx, span, o, f, Some(tables)); + let nice = NiceRegionError::new_from_span(self.infcx, span, o, f); if let Some(diag) = nice.try_report_from_nll() { diag.buffer(&mut self.errors_buffer); return; @@ -430,18 +427,17 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { errci.outlived_fr, ); - let escapes_from = match self.regioncx.universal_regions().defining_ty { - DefiningTy::Closure(..) => "closure", - DefiningTy::Generator(..) => "generator", - DefiningTy::FnDef(..) => "function", - DefiningTy::Const(..) => "const", - }; + let (_, escapes_from) = self + .infcx + .tcx + .article_and_description(self.regioncx.universal_regions().defining_ty.def_id()); // Revert to the normal error in these cases. // Assignments aren't "escapes" in function items. if (fr_name_and_span.is_none() && outlived_fr_name_and_span.is_none()) - || (*category == ConstraintCategory::Assignment && escapes_from == "function") - || escapes_from == "const" + || (*category == ConstraintCategory::Assignment + && self.regioncx.universal_regions().defining_ty.is_fn_def()) + || self.regioncx.universal_regions().defining_ty.is_const() { return self.report_general_error(&ErrorConstraintInfo { fr_is_local: true, @@ -507,8 +503,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut diag = self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough"); - let mir_def_name = - if self.infcx.tcx.is_closure(self.mir_def_id) { "closure" } else { "function" }; + let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id); let fr_name = self.give_region_a_name(*fr).unwrap(); fr_name.highlight_region_name(&mut diag); @@ -588,6 +583,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { found = true; break; + } else { + // If there's already a lifetime bound, don't + // suggest anything. + return; } } } @@ -613,7 +612,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } else { "'_".to_string() }; - let suggestion = if snippet.ends_with(";") { + let suggestion = if snippet.ends_with(';') { // `type X = impl Trait;` format!("{} + {};", &snippet[..snippet.len() - 1], suggestable_fr_name) } else { diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/src/librustc_mir/borrow_check/diagnostics/region_name.rs index 09d61d9ad9a..7103fc596c9 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_name.rs @@ -645,13 +645,13 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { .. }) => ( match return_ty.output { - hir::FunctionRetTy::DefaultReturn(_) => tcx.sess.source_map().end_point(*span), - hir::FunctionRetTy::Return(_) => return_ty.output.span(), + hir::FnRetTy::DefaultReturn(_) => tcx.sess.source_map().end_point(*span), + hir::FnRetTy::Return(_) => return_ty.output.span(), }, if gen_move.is_some() { " of generator" } else { " of closure" }, ), hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Method(method_sig, _), + kind: hir::ImplItemKind::Fn(method_sig, _), .. }) => (method_sig.decl.output.span(), ""), _ => (self.body.span, ""), diff --git a/src/librustc_mir/borrow_check/facts.rs b/src/librustc_mir/borrow_check/facts.rs index 827ccb1c857..cd8139b17b4 100644 --- a/src/librustc_mir/borrow_check/facts.rs +++ b/src/librustc_mir/borrow_check/facts.rs @@ -71,16 +71,16 @@ impl AllFactsExt for AllFacts { killed, outlives, invalidates, - var_used, - var_defined, - var_drop_used, - var_uses_region, - var_drops_region, - child, - path_belongs_to_var, - initialized_at, - moved_out_at, - path_accessed_at, + var_used_at, + var_defined_at, + var_dropped_at, + use_of_var_derefs_origin, + drop_of_var_derefs_origin, + child_path, + path_is_var, + path_assigned_at_base, + path_moved_at_base, + path_accessed_at_base, known_subset, ]) } diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs index 392f164d314..d33639aa9d9 100644 --- a/src/librustc_mir/borrow_check/invalidation.rs +++ b/src/librustc_mir/borrow_check/invalidation.rs @@ -63,7 +63,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.mutate_place(location, lhs, Shallow(None), JustWrite); } StatementKind::FakeRead(_, _) => { - // Only relavent for initialized/liveness/safety checks. + // Only relevant for initialized/liveness/safety checks. } StatementKind::SetDiscriminant { ref place, variant_index: _ } => { self.mutate_place(location, place, Shallow(None), JustWrite); @@ -153,8 +153,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => { self.consume_operand(location, cond); - use rustc::mir::interpret::PanicInfo; - if let PanicInfo::BoundsCheck { ref len, ref index } = *msg { + use rustc::mir::AssertKind; + if let AssertKind::BoundsCheck { ref len, ref index } = *msg { self.consume_operand(location, len); self.consume_operand(location, index); } diff --git a/src/librustc_mir/borrow_check/member_constraints.rs b/src/librustc_mir/borrow_check/member_constraints.rs index c95919685bb..4323e2db844 100644 --- a/src/librustc_mir/borrow_check/member_constraints.rs +++ b/src/librustc_mir/borrow_check/member_constraints.rs @@ -1,5 +1,5 @@ use crate::rustc::ty::{self, Ty}; -use rustc::infer::region_constraints::MemberConstraint; +use rustc::infer::MemberConstraint; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; @@ -125,7 +125,7 @@ where // wind up mapped to the same key `S`, we would append the // linked list for `Ra` onto the end of the linked list for // `Rb` (or vice versa) -- this basically just requires - // rewriting the final link from one list to point at the othe + // rewriting the final link from one list to point at the other // other (see `append_list`). let MemberConstraintSet { first_constraints, mut constraints, choice_regions } = self; diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 88173137bd2..6c1901455fd 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1,8 +1,5 @@ //! This query borrow-checks the MIR to (further) ensure it is not broken. -use rustc::infer::InferCtxt; -use rustc::lint::builtin::MUTABLE_BORROW_RESERVATION_CONFLICT; -use rustc::lint::builtin::UNUSED_MUT; use rustc::mir::{ read_only, traversal, Body, BodyAndCache, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem, PlaceRef, ReadOnlyBodyAndCache, @@ -12,7 +9,7 @@ use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKi use rustc::mir::{Terminator, TerminatorKind}; use rustc::ty::query::Providers; use rustc::ty::{self, RegionVid, TyCtxt}; - +use rustc_ast::ast::Name; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; @@ -20,6 +17,9 @@ use rustc_hir as hir; use rustc_hir::{def_id::DefId, HirId, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT}; +use rustc_span::{Span, DUMMY_SP}; use either::Either; use smallvec::SmallVec; @@ -28,9 +28,6 @@ use std::collections::BTreeMap; use std::mem; use std::rc::Rc; -use rustc_span::{Span, DUMMY_SP}; -use syntax::ast::Name; - use crate::dataflow; use crate::dataflow::generic::{Analysis, BorrowckFlowState as Flows, BorrowckResults}; use crate::dataflow::indexes::{BorrowIndex, InitIndex, MoveOutIndex, MovePathIndex}; @@ -86,11 +83,13 @@ crate struct Upvar { mutability: Mutability, } +const DEREF_PROJECTION: &[PlaceElem<'_>; 1] = &[ProjectionElem::Deref]; + pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { mir_borrowck, ..*providers }; } -fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> BorrowCheckResult<'_> { +fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> &BorrowCheckResult<'_> { let (input_body, promoted) = tcx.mir_validated(def_id); debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id)); @@ -101,7 +100,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> BorrowCheckResult<'_> { }); debug!("mir_borrowck done"); - opt_closure_req + tcx.arena.alloc(opt_closure_req) } fn do_mir_borrowck<'a, 'tcx>( @@ -136,6 +135,9 @@ fn do_mir_borrowck<'a, 'tcx>( // Gather the upvars of a closure, if any. let tables = tcx.typeck_tables_of(def_id); + if tables.tainted_by_errors { + infcx.set_tainted_by_errors(); + } let upvars: Vec<_> = tables .upvar_list .get(&def_id) @@ -195,27 +197,40 @@ fn do_mir_borrowck<'a, 'tcx>( Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data)); // Compute non-lexical lifetimes. - let nll::NllOutput { regioncx, polonius_output, opt_closure_req, nll_errors } = - nll::compute_regions( - infcx, - def_id, - free_regions, - body, - &promoted, - location_table, - param_env, - &mut flow_inits, - &mdpe.move_data, - &borrow_set, - ); + let nll::NllOutput { + regioncx, + opaque_type_values, + polonius_output, + opt_closure_req, + nll_errors, + } = nll::compute_regions( + infcx, + def_id, + free_regions, + body, + &promoted, + location_table, + param_env, + &mut flow_inits, + &mdpe.move_data, + &borrow_set, + ); // Dump MIR results into a file, if that is enabled. This let us // write unit-tests, as well as helping with debugging. nll::dump_mir_results(infcx, MirSource::item(def_id), &body, ®ioncx, &opt_closure_req); - // We also have a `#[rustc_nll]` annotation that causes us to dump + // We also have a `#[rustc_regions]` annotation that causes us to dump // information. - nll::dump_annotation(infcx, &body, def_id, ®ioncx, &opt_closure_req, &mut errors_buffer); + nll::dump_annotation( + infcx, + &body, + def_id, + ®ioncx, + &opt_closure_req, + &opaque_type_values, + &mut errors_buffer, + ); // The various `flow_*` structures can be large. We drop `flow_inits` here // so it doesn't overlap with the others below. This reduces peak memory @@ -349,7 +364,7 @@ fn do_mir_borrowck<'a, 'tcx>( // Skip over locals that begin with an underscore or have no name match mbcx.local_names[local] { Some(name) => { - if name.as_str().starts_with("_") { + if name.as_str().starts_with('_') { continue; } } @@ -389,6 +404,7 @@ fn do_mir_borrowck<'a, 'tcx>( } let result = BorrowCheckResult { + concrete_opaque_types: opaque_type_values, closure_requirements: opt_closure_req, used_mut_upvars: mbcx.used_mut_upvars, }; @@ -435,7 +451,7 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> { /// for the activation of the borrow. reservation_warnings: FxHashMap, Span, Location, BorrowKind, BorrowData<'tcx>)>, - /// This field keeps track of move errors that are to be reported for given move indicies. + /// This field keeps track of move errors that are to be reported for given move indices. /// /// There are situations where many errors can be reported for a single move out (see #53807) /// and we want only the best of those errors. @@ -449,10 +465,10 @@ crate struct MirBorrowckCtxt<'cx, 'tcx> { /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary /// when errors in the map are being re-added to the error buffer so that errors with the /// same primary span come out in a consistent order. - move_error_reported: BTreeMap, (PlaceRef<'cx, 'tcx>, DiagnosticBuilder<'cx>)>, + move_error_reported: BTreeMap, (PlaceRef<'tcx>, DiagnosticBuilder<'cx>)>, /// This field keeps track of errors reported in the checking of uninitialized variables, /// so that we don't report seemingly duplicate errors. - uninitialized_error_reported: FxHashSet>, + uninitialized_error_reported: FxHashSet>, /// Errors to be reported buffer errors_buffer: Vec, /// This field keeps track of all the local variables that are declared mut and are mutated. @@ -654,8 +670,8 @@ impl<'cx, 'tcx> dataflow::generic::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt } TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => { self.consume_operand(loc, (cond, span), flow_state); - use rustc::mir::interpret::PanicInfo; - if let PanicInfo::BoundsCheck { ref len, ref index } = *msg { + use rustc::mir::AssertKind; + if let AssertKind::BoundsCheck { ref len, ref index } = *msg { self.consume_operand(loc, (len, span), flow_state); self.consume_operand(loc, (index, span), flow_state); } @@ -824,9 +840,9 @@ enum InitializationRequiringAction { PartialAssignment, } -struct RootPlace<'d, 'tcx> { +struct RootPlace<'tcx> { place_local: Local, - place_projection: &'d [PlaceElem<'tcx>], + place_projection: &'tcx [PlaceElem<'tcx>], is_local_mutation_allowed: LocalMutationIsAllowed, } @@ -1396,7 +1412,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) { debug!("check_for_invalidation_at_exit({:?})", borrow); let place = &borrow.borrowed_place; - let deref = [ProjectionElem::Deref]; let mut root_place = PlaceRef { local: place.local, projection: &[] }; // FIXME(nll-rfc#40): do more precise destructor tracking here. For now @@ -1410,7 +1425,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Thread-locals might be dropped after the function exits // We have to dereference the outer reference because // borrows don't conflict behind shared references. - root_place.projection = &deref; + root_place.projection = DEREF_PROJECTION; (true, true) } else { (false, self.locals_are_invalidated_at_exit) @@ -1509,7 +1524,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, location: Location, desired_action: InitializationRequiringAction, - place_span: (PlaceRef<'cx, 'tcx>, Span), + place_span: (PlaceRef<'tcx>, Span), flow_state: &Flows<'cx, 'tcx>, ) { let maybe_uninits = &flow_state.uninits; @@ -1575,16 +1590,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, location: Location, desired_action: InitializationRequiringAction, - place_span: (PlaceRef<'cx, 'tcx>, Span), + place_span: (PlaceRef<'tcx>, Span), maybe_uninits: &BitSet, from: u32, to: u32, ) { if let Some(mpi) = self.move_path_for_place(place_span.0) { let move_paths = &self.move_data.move_paths; - let mut child = move_paths[mpi].first_child; - while let Some(child_mpi) = child { - let child_move_path = &move_paths[child_mpi]; + + let root_path = &move_paths[mpi]; + for (child_mpi, child_move_path) in root_path.children(move_paths) { let last_proj = child_move_path.place.projection.last().unwrap(); if let ProjectionElem::ConstantIndex { offset, from_end, .. } = last_proj { debug_assert!(!from_end, "Array constant indexing shouldn't be `from_end`."); @@ -1606,7 +1621,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } - child = child_move_path.next_sibling; } } } @@ -1615,7 +1629,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, location: Location, desired_action: InitializationRequiringAction, - place_span: (PlaceRef<'cx, 'tcx>, Span), + place_span: (PlaceRef<'tcx>, Span), flow_state: &Flows<'cx, 'tcx>, ) { let maybe_uninits = &flow_state.uninits; @@ -1693,10 +1707,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// An Err result includes a tag indicated why the search failed. /// Currently this can only occur if the place is built off of a /// static variable, as we do not track those in the MoveData. - fn move_path_closest_to( - &mut self, - place: PlaceRef<'_, 'tcx>, - ) -> (PlaceRef<'cx, 'tcx>, MovePathIndex) { + fn move_path_closest_to(&mut self, place: PlaceRef<'tcx>) -> (PlaceRef<'tcx>, MovePathIndex) { match self.move_data.rev_lookup.find(place) { LookupResult::Parent(Some(mpi)) | LookupResult::Exact(mpi) => { (self.move_data.move_paths[mpi].place.as_ref(), mpi) @@ -1705,7 +1716,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - fn move_path_for_place(&mut self, place: PlaceRef<'_, 'tcx>) -> Option { + fn move_path_for_place(&mut self, place: PlaceRef<'tcx>) -> Option { // If returns None, then there is no move path corresponding // to a direct owner of `place` (which means there is nothing // that borrowck tracks for its analysis). @@ -1800,7 +1811,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn check_parent_of_field<'cx, 'tcx>( this: &mut MirBorrowckCtxt<'cx, 'tcx>, location: Location, - base: PlaceRef<'cx, 'tcx>, + base: PlaceRef<'tcx>, span: Span, flow_state: &Flows<'cx, 'tcx>, ) { @@ -2013,7 +2024,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } /// Adds the place into the used mutable variables set - fn add_used_mut<'d>(&mut self, root_place: RootPlace<'d, 'tcx>, flow_state: &Flows<'cx, 'tcx>) { + fn add_used_mut(&mut self, root_place: RootPlace<'tcx>, flow_state: &Flows<'cx, 'tcx>) { match root_place { RootPlace { place_local: local, place_projection: [], is_local_mutation_allowed } => { // If the local may have been initialized, and it is now currently being @@ -2047,11 +2058,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Whether this value can be written or borrowed mutably. /// Returns the root place if the place passed in is a projection. - fn is_mutable<'d>( + fn is_mutable( &self, - place: PlaceRef<'d, 'tcx>, + place: PlaceRef<'tcx>, is_local_mutation_allowed: LocalMutationIsAllowed, - ) -> Result, PlaceRef<'d, 'tcx>> { + ) -> Result, PlaceRef<'tcx>> { match place { PlaceRef { local, projection: [] } => { let local = &self.body.local_decls[local]; @@ -2202,7 +2213,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// then returns the index of the field being projected. Note that this closure will always /// be `self` in the current MIR, because that is the only time we directly access the fields /// of a closure type. - pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'cx, 'tcx>) -> Option { + pub fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option { let mut place_projection = place_ref.projection; let mut by_ref = false; diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index a71dfc9a778..077ed49ed2c 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -1,14 +1,15 @@ //! The entry point of the NLL borrow checker. -use rustc::infer::InferCtxt; use rustc::mir::{ BasicBlock, Body, BodyAndCache, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted, ReadOnlyBodyAndCache, }; use rustc::ty::{self, RegionKind, RegionVid}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::Diagnostic; use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; +use rustc_infer::infer::InferCtxt; use rustc_span::symbol::sym; use std::env; use std::fmt::Debug; @@ -46,6 +47,7 @@ crate type PoloniusOutput = Output; /// closure requirements to propagate, and any generated errors. crate struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, + pub opaque_type_values: FxHashMap>, pub polonius_output: Option>, pub opt_closure_req: Option>, pub nll_errors: RegionErrors<'tcx>, @@ -84,15 +86,18 @@ fn populate_polonius_move_facts( body: &Body<'_>, ) { all_facts - .path_belongs_to_var + .path_is_var .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(v, &m)| (m, v))); for (child, move_path) in move_data.move_paths.iter_enumerated() { - all_facts - .child - .extend(move_path.parents(&move_data.move_paths).iter().map(|&parent| (child, parent))); + if let Some(parent) = move_path.parent { + all_facts.child_path.push((child, parent)); + } } + let fn_entry_start = location_table + .start_index(Location { block: BasicBlock::from_u32(0u32), statement_index: 0 }); + // initialized_at for init in move_data.inits.iter() { match init.location { @@ -113,28 +118,37 @@ fn populate_polonius_move_facts( // the successors, but not in the unwind block. let first_statement = Location { block: successor, statement_index: 0 }; all_facts - .initialized_at + .path_assigned_at_base .push((init.path, location_table.start_index(first_statement))); } } else { // In all other cases, the initialization just happens at the // midpoint, like any other effect. - all_facts.initialized_at.push((init.path, location_table.mid_index(location))); + all_facts + .path_assigned_at_base + .push((init.path, location_table.mid_index(location))); } } // Arguments are initialized on function entry InitLocation::Argument(local) => { assert!(body.local_kind(local) == LocalKind::Arg); - let fn_entry = Location { block: BasicBlock::from_u32(0u32), statement_index: 0 }; - all_facts.initialized_at.push((init.path, location_table.start_index(fn_entry))); + all_facts.path_assigned_at_base.push((init.path, fn_entry_start)); } } } + for (local, &path) in move_data.rev_lookup.iter_locals_enumerated() { + if body.local_kind(local) != LocalKind::Arg { + // Non-arguments start out deinitialised; we simulate this with an + // initial move: + all_facts.path_moved_at_base.push((path, fn_entry_start)); + } + } + // moved_out_at // deinitialisation is assumed to always happen! all_facts - .moved_out_at + .path_moved_at_base .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source)))); } @@ -160,20 +174,21 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( let elements = &Rc::new(RegionValueElements::new(&body)); // Run the MIR type-checker. - let MirTypeckResults { constraints, universal_region_relations } = type_check::type_check( - infcx, - param_env, - body, - promoted, - def_id, - &universal_regions, - location_table, - borrow_set, - &mut all_facts, - flow_inits, - move_data, - elements, - ); + let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = + type_check::type_check( + infcx, + param_env, + body, + promoted, + def_id, + &universal_regions, + location_table, + borrow_set, + &mut all_facts, + flow_inits, + move_data, + elements, + ); if let Some(all_facts) = &mut all_facts { let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation"); @@ -257,7 +272,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( // Dump facts if requested. let polonius_output = all_facts.and_then(|all_facts| { if infcx.tcx.sess.opts.debugging_opts.nll_facts { - let def_path = infcx.tcx.hir().def_path(def_id); + let def_path = infcx.tcx.def_path(def_id); let dir_path = PathBuf::from("nll-facts").join(def_path.to_filename_friendly_no_crate()); all_facts.write_to_dir(dir_path, location_table).unwrap(); @@ -279,8 +294,16 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( let (closure_region_requirements, nll_errors) = regioncx.solve(infcx, &body, def_id, polonius_output.clone()); + if !nll_errors.is_empty() { + // Suppress unhelpful extra errors in `infer_opaque_types`. + infcx.set_tainted_by_errors(); + } + + let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values, body.span); + NllOutput { regioncx, + opaque_type_values: remapped_opaque_tys, polonius_output, opt_closure_req: closure_region_requirements, nll_errors, @@ -344,6 +367,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( mir_def_id: DefId, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, + opaque_type_values: &FxHashMap>, errors_buffer: &mut Vec, ) { let tcx = infcx.tcx; @@ -359,7 +383,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( // viewing the intraprocedural state, the -Zdump-mir output is // better. - if let Some(closure_region_requirements) = closure_region_requirements { + let mut err = if let Some(closure_region_requirements) = closure_region_requirements { let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "external requirements"); regioncx.annotate(tcx, &mut err); @@ -377,13 +401,19 @@ pub(super) fn dump_annotation<'a, 'tcx>( }) .unwrap(); - err.buffer(errors_buffer); + err } else { let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "no external requirements"); regioncx.annotate(tcx, &mut err); - err.buffer(errors_buffer); + err + }; + + if !opaque_type_values.is_empty() { + err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values)); } + + err.buffer(errors_buffer); } fn for_each_region_constraint( diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 984de021ca1..767ffa50fed 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -48,7 +48,7 @@ pub(super) fn borrow_conflicts_with_place<'tcx>( body: &Body<'tcx>, borrow_place: &Place<'tcx>, borrow_kind: BorrowKind, - access_place: PlaceRef<'_, 'tcx>, + access_place: PlaceRef<'tcx>, access: AccessDepth, bias: PlaceConflictBias, ) -> bool { @@ -73,7 +73,7 @@ fn place_components_conflict<'tcx>( body: &Body<'tcx>, borrow_place: &Place<'tcx>, borrow_kind: BorrowKind, - access_place: PlaceRef<'_, 'tcx>, + access_place: PlaceRef<'tcx>, access: AccessDepth, bias: PlaceConflictBias, ) -> bool { diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index 31bee460fa0..c64e8c363af 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -13,12 +13,12 @@ use rustc::mir::{Place, PlaceRef, ProjectionElem, ReadOnlyBodyAndCache}; use rustc::ty::{self, TyCtxt}; use rustc_hir as hir; -pub trait IsPrefixOf<'cx, 'tcx> { - fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool; +pub trait IsPrefixOf<'tcx> { + fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool; } -impl<'cx, 'tcx> IsPrefixOf<'cx, 'tcx> for PlaceRef<'cx, 'tcx> { - fn is_prefix_of(&self, other: PlaceRef<'cx, 'tcx>) -> bool { +impl<'tcx> IsPrefixOf<'tcx> for PlaceRef<'tcx> { + fn is_prefix_of(&self, other: PlaceRef<'tcx>) -> bool { self.local == other.local && self.projection.len() <= other.projection.len() && self.projection == &other.projection[..self.projection.len()] @@ -29,7 +29,7 @@ pub(super) struct Prefixes<'cx, 'tcx> { body: ReadOnlyBodyAndCache<'cx, 'tcx>, tcx: TyCtxt<'tcx>, kind: PrefixSet, - next: Option>, + next: Option>, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -50,7 +50,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// terminating the iteration early based on `kind`. pub(super) fn prefixes( &self, - place_ref: PlaceRef<'cx, 'tcx>, + place_ref: PlaceRef<'tcx>, kind: PrefixSet, ) -> Prefixes<'cx, 'tcx> { Prefixes { next: Some(place_ref), kind, body: self.body, tcx: self.infcx.tcx } @@ -58,7 +58,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { - type Item = PlaceRef<'cx, 'tcx>; + type Item = PlaceRef<'tcx>; fn next(&mut self) -> Option { let mut cursor = self.next?; diff --git a/src/librustc_mir/borrow_check/region_infer/dump_mir.rs b/src/librustc_mir/borrow_check/region_infer/dump_mir.rs index b236ffe8074..369e5402311 100644 --- a/src/librustc_mir/borrow_check/region_infer/dump_mir.rs +++ b/src/librustc_mir/borrow_check/region_infer/dump_mir.rs @@ -4,7 +4,7 @@ //! context internal state. use super::{OutlivesConstraint, RegionInferenceContext}; -use rustc::infer::NLLRegionVariableOrigin; +use rustc_infer::infer::NLLRegionVariableOrigin; use std::io::{self, Write}; // Room for "'_#NNNNr" before things get misaligned. diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 6abca481eac..fe96b3e34a2 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -1,22 +1,21 @@ use std::collections::VecDeque; use std::rc::Rc; -use rustc::infer::canonical::QueryOutlivesConstraint; -use rustc::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; -use rustc::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin}; use rustc::mir::{ Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory, Local, Location, }; use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::binary_search_util; +use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::scc::Sccs; -use rustc_data_structures::graph::vec_graph::VecGraph; -use rustc_data_structures::graph::WithSuccessors; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; +use rustc_infer::infer::canonical::QueryOutlivesConstraint; +use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; +use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin}; use rustc_span::Span; use crate::borrow_check::{ @@ -26,6 +25,7 @@ use crate::borrow_check::{ diagnostics::{RegionErrorKind, RegionErrors}, member_constraints::{MemberConstraintSet, NllMemberConstraintIndex}, nll::{PoloniusOutput, ToRegionVid}, + region_infer::reverse_sccs::ReverseSccGraph, region_infer::values::{ LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues, ToElementIndex, @@ -36,6 +36,8 @@ use crate::borrow_check::{ mod dump_mir; mod graphviz; +mod opaque_types; +mod reverse_sccs; pub mod values; @@ -53,21 +55,22 @@ pub struct RegionInferenceContext<'tcx> { liveness_constraints: LivenessValues, /// The outlives constraints computed by the type-check. - constraints: Rc, + constraints: Frozen, /// The constraint-set, but in graph form, making it easy to traverse /// the constraints adjacent to a particular region. Used to construct /// the SCC (see `constraint_sccs`) and for error reporting. - constraint_graph: Rc, + constraint_graph: Frozen, /// The SCC computed from `constraints` and the constraint /// graph. We have an edge from SCC A to SCC B if `A: B`. Used to /// compute the values of each region. constraint_sccs: Rc>, - /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` - /// exists if `B: A`. Computed lazilly. - rev_constraint_graph: Option>>, + /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if + /// `B: A`. This is used to compute the universal regions that are required + /// to outlive a given SCC. Computed lazily. + rev_scc_graph: Option>, /// The "R0 member of [R1..Rn]" constraints, indexed by SCC. member_constraints: Rc>, @@ -110,7 +113,7 @@ pub struct RegionInferenceContext<'tcx> { /// Information about how the universally quantified regions in /// scope on this function relate to one another. - universal_region_relations: Rc>, + universal_region_relations: Frozen>, } /// Each time that `apply_member_constraint` is successful, it appends @@ -240,11 +243,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// The `outlives_constraints` and `type_tests` are an initial set /// of constraints produced by the MIR type check. - pub(crate) fn new( + pub(in crate::borrow_check) fn new( var_infos: VarInfos, universal_regions: Rc>, placeholder_indices: Rc, - universal_region_relations: Rc>, + universal_region_relations: Frozen>, outlives_constraints: OutlivesConstraintSet, member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, closure_bounds_mapping: FxHashMap< @@ -261,8 +264,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { .map(|info| RegionDefinition::new(info.universe, info.origin)) .collect(); - let constraints = Rc::new(outlives_constraints); // freeze constraints - let constraint_graph = Rc::new(constraints.graph(definitions.len())); + let constraints = Frozen::freeze(outlives_constraints); + let constraint_graph = Frozen::freeze(constraints.graph(definitions.len())); let fr_static = universal_regions.fr_static; let constraint_sccs = Rc::new(constraints.compute_sccs(&constraint_graph, fr_static)); @@ -287,7 +290,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { constraints, constraint_graph, constraint_sccs, - rev_constraint_graph: None, + rev_scc_graph: None, member_constraints, member_constraints_applied: Vec::new(), closure_bounds_mapping, @@ -510,7 +513,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.check_universal_regions(body, outlives_requirements.as_mut(), &mut errors_buffer); } - self.check_member_constraints(infcx, &mut errors_buffer); + if errors_buffer.is_empty() { + self.check_member_constraints(infcx, &mut errors_buffer); + } let outlives_requirements = outlives_requirements.unwrap_or(vec![]); @@ -677,15 +682,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { // free region that must outlive the member region `R0` (`UB: // R0`). Therefore, we need only keep an option `O` if `UB: O` // for all UB. - if choice_regions.len() > 1 { - let universal_region_relations = self.universal_region_relations.clone(); - let rev_constraint_graph = self.rev_constraint_graph(); - for ub in self.upper_bounds(scc, &rev_constraint_graph) { - debug!("apply_member_constraint: ub={:?}", ub); - choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r)); - } - debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions); + let rev_scc_graph = self.reverse_scc_graph(); + let universal_region_relations = &self.universal_region_relations; + for ub in rev_scc_graph.upper_bounds(scc) { + debug!("apply_member_constraint: ub={:?}", ub); + choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r)); } + debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions); // If we ruled everything out, we're done. if choice_regions.is_empty() { @@ -741,32 +744,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { } } - /// Compute and return the reverse SCC-based constraint graph (lazilly). - fn upper_bounds( - &'a mut self, - scc0: ConstraintSccIndex, - rev_constraint_graph: &'a VecGraph, - ) -> impl Iterator + 'a { - let scc_values = &self.scc_values; - let mut duplicates = FxHashSet::default(); - rev_constraint_graph - .depth_first_search(scc0) - .skip(1) - .flat_map(move |scc1| scc_values.universal_regions_outlived_by(scc1)) - .filter(move |&r| duplicates.insert(r)) - } - - /// Compute and return the reverse SCC-based constraint graph (lazilly). - fn rev_constraint_graph(&mut self) -> Rc> { - if let Some(g) = &self.rev_constraint_graph { - return g.clone(); - } - - let rev_graph = Rc::new(self.constraint_sccs.reverse()); - self.rev_constraint_graph = Some(rev_graph.clone()); - rev_graph - } - /// Returns `true` if all the elements in the value of `scc_b` are nameable /// in `scc_a`. Used during constraint propagation, and only once /// the value of `scc_b` has been computed. @@ -1603,7 +1580,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // If not, report an error. let member_region = infcx.tcx.mk_region(ty::ReVar(member_region_vid)); errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion { - opaque_type_def_id: m_c.opaque_type_def_id, + span: m_c.definition_span, hidden_ty: m_c.hidden_ty, member_region, }); diff --git a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs new file mode 100644 index 00000000000..49b49437328 --- /dev/null +++ b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs @@ -0,0 +1,150 @@ +use rustc::ty::{self, TyCtxt, TypeFoldable}; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::DefId; +use rustc_infer::infer::InferCtxt; +use rustc_span::Span; +use rustc_trait_selection::opaque_types::InferCtxtExt; + +use super::RegionInferenceContext; + +impl<'tcx> RegionInferenceContext<'tcx> { + /// Resolve any opaque types that were encountered while borrow checking + /// this item. This is then used to get the type in the `type_of` query. + /// + /// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`. + /// This is lowered to give HIR something like + /// + /// type f<'a>::_Return<'_a> = impl Sized + '_a; + /// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x } + /// + /// When checking the return type record the type from the return and the + /// type used in the return value. In this case they might be `_Return<'1>` + /// and `&'2 i32` respectively. + /// + /// Once we to this method, we have completed region inference and want to + /// call `infer_opaque_definition_from_instantiation` to get the inferred + /// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation` + /// compares lifetimes directly, so we need to map the inference variables + /// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`. + /// + /// First we map all the lifetimes in the concrete type to an equal + /// universal region that occurs in the concrete type's substs, in this case + /// this would result in `&'1 i32`. We only consider regions in the substs + /// in case there is an equal region that does not. For example, this should + /// be allowed: + /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }` + /// + /// Then we map the regions in both the type and the subst to their + /// `external_name` giving `concrete_type = &'a i32`, + /// `substs = ['static, 'a]`. This will then allow + /// `infer_opaque_definition_from_instantiation` to determine that + /// `_Return<'_a> = &'_a i32`. + /// + /// There's a slight complication around closures. Given + /// `fn f<'a: 'a>() { || {} }` the closure's type is something like + /// `f::<'a>::{{closure}}`. The region parameter from f is essentially + /// ignored by type checking so ends up being inferred to an empty region. + /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`, + /// which has no `external_name` in which case we use `'empty` as the + /// region to pass to `infer_opaque_definition_from_instantiation`. + pub(in crate::borrow_check) fn infer_opaque_types( + &self, + infcx: &InferCtxt<'_, 'tcx>, + opaque_ty_decls: FxHashMap>, + span: Span, + ) -> FxHashMap> { + opaque_ty_decls + .into_iter() + .map(|(opaque_def_id, ty::ResolvedOpaqueTy { concrete_type, substs })| { + debug!( + "infer_opaque_types(concrete_type = {:?}, substs = {:?})", + concrete_type, substs + ); + + let mut subst_regions = vec![self.universal_regions.fr_static]; + let universal_substs = + infcx.tcx.fold_regions(&substs, &mut false, |region, _| match *region { + ty::ReVar(vid) => { + subst_regions.push(vid); + self.definitions[vid].external_name.unwrap_or_else(|| { + infcx.tcx.sess.delay_span_bug( + span, + "opaque type with non-universal region substs", + ); + infcx.tcx.lifetimes.re_static + }) + } + // We don't fold regions in the predicates of opaque + // types to `ReVar`s. This means that in a case like + // + // fn f<'a: 'a>() -> impl Iterator + // + // The inner opaque type has `'static` in its substs. + ty::ReStatic => region, + _ => { + infcx.tcx.sess.delay_span_bug( + span, + &format!("unexpected concrete region in borrowck: {:?}", region), + ); + region + } + }); + + subst_regions.sort(); + subst_regions.dedup(); + + let universal_concrete_type = + infcx.tcx.fold_regions(&concrete_type, &mut false, |region, _| match *region { + ty::ReVar(vid) => subst_regions + .iter() + .find(|ur_vid| self.eval_equal(vid, **ur_vid)) + .and_then(|ur_vid| self.definitions[*ur_vid].external_name) + .unwrap_or(infcx.tcx.lifetimes.re_root_empty), + ty::ReLateBound(..) => region, + _ => { + infcx.tcx.sess.delay_span_bug( + span, + &format!("unexpected concrete region in borrowck: {:?}", region), + ); + region + } + }); + + debug!( + "infer_opaque_types(universal_concrete_type = {:?}, universal_substs = {:?})", + universal_concrete_type, universal_substs + ); + + let remapped_type = infcx.infer_opaque_definition_from_instantiation( + opaque_def_id, + universal_substs, + universal_concrete_type, + span, + ); + ( + opaque_def_id, + ty::ResolvedOpaqueTy { concrete_type: remapped_type, substs: universal_substs }, + ) + }) + .collect() + } + + /// Map the regions in the type to named regions. This is similar to what + /// `infer_opaque_types` does, but can infer any universal region, not only + /// ones from the substs for the opaque type. It also doesn't double check + /// that the regions produced are in fact equal to the named region they are + /// replaced with. This is fine because this function is only to improve the + /// region names in error messages. + pub(in crate::borrow_check) fn name_regions(&self, tcx: TyCtxt<'tcx>, ty: T) -> T + where + T: TypeFoldable<'tcx>, + { + tcx.fold_regions(&ty, &mut false, |region, _| match *region { + ty::ReVar(vid) => { + let upper_bound = self.universal_upper_bound(vid); + self.definitions[upper_bound].external_name.unwrap_or(region) + } + _ => region, + }) + } +} diff --git a/src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs b/src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs new file mode 100644 index 00000000000..ff19ac5f21a --- /dev/null +++ b/src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs @@ -0,0 +1,68 @@ +use crate::borrow_check::constraints::ConstraintSccIndex; +use crate::borrow_check::RegionInferenceContext; +use itertools::Itertools; +use rustc::ty::RegionVid; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::graph::vec_graph::VecGraph; +use rustc_data_structures::graph::WithSuccessors; +use std::ops::Range; +use std::rc::Rc; + +crate struct ReverseSccGraph { + graph: VecGraph, + /// For each SCC, the range of `universal_regions` that use that SCC as + /// their value. + scc_regions: FxHashMap>, + /// All of the universal regions, in grouped so that `scc_regions` can + /// index into here. + universal_regions: Vec, +} + +impl ReverseSccGraph { + /// Find all universal regions that are required to outlive the given SCC. + pub(super) fn upper_bounds<'a>( + &'a self, + scc0: ConstraintSccIndex, + ) -> impl Iterator + 'a { + let mut duplicates = FxHashSet::default(); + self.graph + .depth_first_search(scc0) + .flat_map(move |scc1| { + self.scc_regions + .get(&scc1) + .map_or(&[][..], |range| &self.universal_regions[range.clone()]) + }) + .copied() + .filter(move |r| duplicates.insert(*r)) + } +} + +impl RegionInferenceContext<'_> { + /// Compute and return the reverse SCC-based constraint graph (lazily). + pub(super) fn reverse_scc_graph(&mut self) -> Rc { + if let Some(g) = &self.rev_scc_graph { + return g.clone(); + } + + let graph = self.constraint_sccs.reverse(); + let mut paired_scc_regions = self + .universal_regions + .universal_regions() + .map(|region| (self.constraint_sccs.scc(region), region)) + .collect_vec(); + paired_scc_regions.sort(); + let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect(); + + let mut scc_regions = FxHashMap::default(); + let mut start = 0; + for (scc, group) in &paired_scc_regions.into_iter().group_by(|(scc, _)| *scc) { + let group_size = group.count(); + scc_regions.insert(scc, start..start + group_size); + start += group_size; + } + + let rev_graph = Rc::new(ReverseSccGraph { graph, scc_regions, universal_regions }); + self.rev_scc_graph = Some(rev_graph.clone()); + rev_graph + } +} diff --git a/src/librustc_mir/borrow_check/region_infer/values.rs b/src/librustc_mir/borrow_check/region_infer/values.rs index 3126d44014b..675463cb1c1 100644 --- a/src/librustc_mir/borrow_check/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/region_infer/values.rs @@ -140,7 +140,7 @@ impl LivenessValues { /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. crate fn new(elements: Rc) -> Self { - Self { points: SparseBitMatrix::new(elements.num_points), elements: elements } + Self { points: SparseBitMatrix::new(elements.num_points), elements } } /// Iterate through each region that has a value in this set. diff --git a/src/librustc_mir/borrow_check/renumber.rs b/src/librustc_mir/borrow_check/renumber.rs index ab08cb0a319..a63d18c27f1 100644 --- a/src/librustc_mir/borrow_check/renumber.rs +++ b/src/librustc_mir/borrow_check/renumber.rs @@ -1,9 +1,9 @@ -use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::mir::{BodyAndCache, Location, PlaceElem, Promoted}; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_index::vec::IndexVec; +use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin}; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. diff --git a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs index a3e38cd7a5f..576759c2a35 100644 --- a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs +++ b/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs @@ -1,12 +1,12 @@ -use rustc::infer::canonical::QueryOutlivesConstraint; -use rustc::infer::canonical::QueryRegionConstraints; -use rustc::infer::outlives::env::RegionBoundPairs; -use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; -use rustc::infer::region_constraints::{GenericKind, VerifyBound}; -use rustc::infer::{self, InferCtxt, SubregionOrigin}; use rustc::mir::ConstraintCategory; use rustc::ty::subst::GenericArgKind; use rustc::ty::{self, TyCtxt}; +use rustc_infer::infer::canonical::QueryOutlivesConstraint; +use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::outlives::env::RegionBoundPairs; +use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; +use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; +use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_span::DUMMY_SP; use crate::borrow_check::{ diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs index cf8c3449d66..86951f93f0e 100644 --- a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs @@ -1,13 +1,15 @@ -use rustc::infer::canonical::QueryRegionConstraints; -use rustc::infer::region_constraints::GenericKind; -use rustc::infer::InferCtxt; use rustc::mir::ConstraintCategory; -use rustc::traits::query::outlives_bounds::{self, OutlivesBound}; -use rustc::traits::query::type_op::{self, TypeOp}; +use rustc::traits::query::OutlivesBound; use rustc::ty::free_region_map::FreeRegionRelations; use rustc::ty::{self, RegionVid, Ty, TyCtxt}; +use rustc_data_structures::frozen::Frozen; use rustc_data_structures::transitive_relation::TransitiveRelation; +use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::outlives; +use rustc_infer::infer::region_constraints::GenericKind; +use rustc_infer::infer::InferCtxt; use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; use crate::borrow_check::{ @@ -52,7 +54,7 @@ type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>; type NormalizedInputsAndOutput<'tcx> = Vec>; crate struct CreateResult<'tcx> { - crate universal_region_relations: Rc>, + pub(in crate::borrow_check) universal_region_relations: Frozen>, crate region_bound_pairs: RegionBoundPairs<'tcx>, crate normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, } @@ -266,7 +268,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { // Insert the facts we know from the predicates. Why? Why not. let param_env = self.param_env; - self.add_outlives_bounds(outlives_bounds::explicit_outlives_bounds(param_env)); + self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env)); // Finally: // - outlives is reflexive, so `'r: 'r` for every region `'r` @@ -297,7 +299,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { } CreateResult { - universal_region_relations: Rc::new(self.relations), + universal_region_relations: Frozen::freeze(self.relations), region_bound_pairs: self.region_bound_pairs, normalized_inputs_and_output, } diff --git a/src/librustc_mir/borrow_check/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs index 3d3b1e5cbf6..37cf77b7095 100644 --- a/src/librustc_mir/borrow_check/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/type_check/input_output.rs @@ -7,9 +7,9 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). -use rustc::infer::LateBoundRegionConversionTime; use rustc::mir::*; use rustc::ty::Ty; +use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_index::vec::Idx; use rustc_span::Span; diff --git a/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs b/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs index 055415f2872..407e0628b6e 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs @@ -12,12 +12,12 @@ type VarPointRelation = Vec<(Local, LocationIndex)>; type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>; struct UseFactsExtractor<'me> { - var_defined: &'me mut VarPointRelation, - var_used: &'me mut VarPointRelation, + var_defined_at: &'me mut VarPointRelation, + var_used_at: &'me mut VarPointRelation, location_table: &'me LocationTable, - var_drop_used: &'me mut Vec<(Local, Location)>, + var_dropped_at: &'me mut VarPointRelation, move_data: &'me MoveData<'me>, - path_accessed_at: &'me mut PathPointRelation, + path_accessed_at_base: &'me mut PathPointRelation, } // A Visitor to walk through the MIR and extract point-wise facts @@ -28,22 +28,22 @@ impl UseFactsExtractor<'_> { fn insert_def(&mut self, local: Local, location: Location) { debug!("UseFactsExtractor::insert_def()"); - self.var_defined.push((local, self.location_to_index(location))); + self.var_defined_at.push((local, self.location_to_index(location))); } fn insert_use(&mut self, local: Local, location: Location) { debug!("UseFactsExtractor::insert_use()"); - self.var_used.push((local, self.location_to_index(location))); + self.var_used_at.push((local, self.location_to_index(location))); } fn insert_drop_use(&mut self, local: Local, location: Location) { debug!("UseFactsExtractor::insert_drop_use()"); - self.var_drop_used.push((local, location)); + self.var_dropped_at.push((local, self.location_to_index(location))); } fn insert_path_access(&mut self, path: MovePathIndex, location: Location) { debug!("UseFactsExtractor::insert_path_access({:?}, {:?})", path, location); - self.path_accessed_at.push((path, self.location_to_index(location))); + self.path_accessed_at_base.push((path, self.location_table.start_index(location))); } fn place_to_mpi(&self, place: &Place<'_>) -> Option { @@ -88,51 +88,54 @@ pub(super) fn populate_access_facts( body: ReadOnlyBodyAndCache<'_, 'tcx>, location_table: &LocationTable, move_data: &MoveData<'_>, - drop_used: &mut Vec<(Local, Location)>, + dropped_at: &mut Vec<(Local, Location)>, ) { debug!("populate_access_facts()"); if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() { let mut extractor = UseFactsExtractor { - var_defined: &mut facts.var_defined, - var_used: &mut facts.var_used, - var_drop_used: drop_used, - path_accessed_at: &mut facts.path_accessed_at, + var_defined_at: &mut facts.var_defined_at, + var_used_at: &mut facts.var_used_at, + var_dropped_at: &mut facts.var_dropped_at, + path_accessed_at_base: &mut facts.path_accessed_at_base, location_table, move_data, }; extractor.visit_body(body); - facts.var_drop_used.extend( - drop_used.iter().map(|&(local, location)| (local, location_table.mid_index(location))), + facts.var_dropped_at.extend( + dropped_at.iter().map(|&(local, location)| (local, location_table.mid_index(location))), ); for (local, local_decl) in body.local_decls.iter_enumerated() { - debug!("add var_uses_regions facts - local={:?}, type={:?}", local, local_decl.ty); + debug!( + "add use_of_var_derefs_origin facts - local={:?}, type={:?}", + local, local_decl.ty + ); let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); let universal_regions = &typeck.borrowck_context.universal_regions; typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| { let region_vid = universal_regions.to_region_vid(region); - facts.var_uses_region.push((local, region_vid)); + facts.use_of_var_derefs_origin.push((local, region_vid)); }); } } } // For every potentially drop()-touched region `region` in `local`'s type -// (`kind`), emit a Polonius `var_drops_region(local, region)` fact. -pub(super) fn add_var_drops_regions( +// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact. +pub(super) fn add_drop_of_var_derefs_origin( typeck: &mut TypeChecker<'_, 'tcx>, local: Local, kind: &GenericArg<'tcx>, ) { - debug!("add_var_drops_region(local={:?}, kind={:?}", local, kind); + debug!("add_drop_of_var_derefs_origin(local={:?}, kind={:?}", local, kind); if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() { let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation"); let universal_regions = &typeck.borrowck_context.universal_regions; typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| { let region_vid = universal_regions.to_region_vid(drop_live_region); - facts.var_drops_region.push((local, region_vid)); + facts.drop_of_var_derefs_origin.push((local, region_vid)); }); } } diff --git a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs index 198f4b4b42e..0c49ee44f9a 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs @@ -1,11 +1,11 @@ -use rustc::infer::canonical::QueryRegionConstraints; use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, ReadOnlyBodyAndCache}; -use rustc::traits::query::dropck_outlives::DropckOutlivesResult; -use rustc::traits::query::type_op::outlives::DropckOutlives; -use rustc::traits::query::type_op::TypeOp; use rustc::ty::{Ty, TypeFoldable}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::bit_set::HybridBitSet; +use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult; +use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; +use rustc_trait_selection::traits::query::type_op::TypeOp; use std::rc::Rc; use crate::dataflow::generic::ResultsCursor; @@ -484,7 +484,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> { for &kind in &drop_data.dropck_result.kinds { Self::make_all_regions_live(self.elements, &mut self.typeck, kind, live_at); - polonius::add_var_drops_regions(&mut self.typeck, dropped_local, &kind); + polonius::add_drop_of_var_derefs_origin(&mut self.typeck, dropped_local, &kind); } } diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 4cbe4145589..05d4fc8880e 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -5,18 +5,10 @@ use std::{fmt, iter, mem}; use either::Either; -use rustc::infer::canonical::QueryRegionConstraints; -use rustc::infer::outlives::env::RegionBoundPairs; -use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin}; -use rustc::mir::interpret::PanicInfo; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; +use rustc::mir::AssertKind; use rustc::mir::*; -use rustc::traits::query::type_op; -use rustc::traits::query::type_op::custom::CustomTypeOp; -use rustc::traits::query::{Fallible, NoSolution}; -use rustc::traits::{self, ObligationCause, PredicateObligations}; use rustc::ty::adjustment::PointerCast; use rustc::ty::cast::CastTy; use rustc::ty::fold::TypeFoldable; @@ -26,12 +18,26 @@ use rustc::ty::{ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, RegionVid, ToPolyTraitRef, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, }; +use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; +use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::outlives::env::RegionBoundPairs; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::{ + InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin, +}; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt}; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::query::type_op; +use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; +use rustc_trait_selection::traits::query::{Fallible, NoSolution}; +use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}; use crate::dataflow::generic::ResultsCursor; use crate::dataflow::move_paths::MoveData; @@ -158,7 +164,7 @@ pub(crate) fn type_check<'mir, 'tcx>( constraints: &mut constraints, }; - type_check_internal( + let opaque_type_values = type_check_internal( infcx, mir_def_id, param_env, @@ -173,10 +179,11 @@ pub(crate) fn type_check<'mir, 'tcx>( liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); translate_outlives_facts(&mut cx); + cx.opaque_type_values }, ); - MirTypeckResults { constraints, universal_region_relations } + MirTypeckResults { constraints, universal_region_relations, opaque_type_values } } fn type_check_internal<'a, 'tcx, R>( @@ -189,7 +196,7 @@ fn type_check_internal<'a, 'tcx, R>( implicit_region_bound: ty::Region<'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, universal_region_relations: &'a UniversalRegionRelations<'tcx>, - mut extra: impl FnMut(&mut TypeChecker<'a, 'tcx>) -> R, + extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R, ) -> R { let mut checker = TypeChecker::new( infcx, @@ -212,7 +219,7 @@ fn type_check_internal<'a, 'tcx, R>( checker.typeck_mir(body); } - extra(&mut checker) + extra(checker) } fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { @@ -309,6 +316,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { ); } } else { + let tcx = self.tcx(); if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.literal.val { if let Some(promoted) = promoted { let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, @@ -358,10 +366,23 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { ); } } + } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { + let unnormalized_ty = tcx.type_of(static_def_id); + let locations = location.to_locations(); + let normalized_ty = self.cx.normalize(unnormalized_ty, locations); + let literal_ty = constant.literal.ty.builtin_deref(true).unwrap().ty; + + if let Err(terr) = self.cx.eq_types( + normalized_ty, + literal_ty, + locations, + ConstraintCategory::Boring, + ) { + span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr); + } } - if let ty::FnDef(def_id, substs) = constant.literal.ty.kind { - let tcx = self.tcx(); + if let ty::FnDef(def_id, substs) = constant.literal.ty.kind { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); self.cx.normalize_and_prove_instantiated_predicates( instantiated_predicates, @@ -466,33 +487,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty); - if place.projection.is_empty() { - if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { - let tcx = self.tcx(); - let trait_ref = ty::TraitRef { - def_id: tcx.lang_items().copy_trait().unwrap(), - substs: tcx.mk_substs_trait(place_ty.ty, &[]), - }; - - // To have a `Copy` operand, the type `T` of the - // value must be `Copy`. Note that we prove that `T: Copy`, - // rather than using the `is_copy_modulo_regions` - // test. This is important because - // `is_copy_modulo_regions` ignores the resulting region - // obligations and assumes they pass. This can result in - // bounds from `Copy` impls being unsoundly ignored (e.g., - // #29149). Note that we decide to use `Copy` before knowing - // whether the bounds fully apply: in effect, the rule is - // that if a value of some type could implement `Copy`, then - // it must. - self.cx.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::CopyBound, - ); - } - } - for elem in place.projection.iter() { if place_ty.variant_index.is_none() { if place_ty.ty.references_error() { @@ -503,6 +497,31 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { place_ty = self.sanitize_projection(place_ty, elem, place, location) } + if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { + let tcx = self.tcx(); + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().copy_trait().unwrap(), + substs: tcx.mk_substs_trait(place_ty.ty, &[]), + }; + + // To have a `Copy` operand, the type `T` of the + // value must be `Copy`. Note that we prove that `T: Copy`, + // rather than using the `is_copy_modulo_regions` + // test. This is important because + // `is_copy_modulo_regions` ignores the resulting region + // obligations and assumes they pass. This can result in + // bounds from `Copy` impls being unsoundly ignored (e.g., + // #29149). Note that we decide to use `Copy` before knowing + // whether the bounds fully apply: in effect, the rule is + // that if a value of some type could implement `Copy`, then + // it must. + self.cx.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::CopyBound, + ); + } + place_ty } @@ -563,7 +582,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { | ConstraintCategory::UseAsConst | ConstraintCategory::UseAsStatic = constraint.category { - // "Returning" from a promoted is an assigment to a + // "Returning" from a promoted is an assignment to a // temporary from the user's point of view. constraint.category = ConstraintCategory::Boring; } @@ -799,6 +818,7 @@ struct TypeChecker<'a, 'tcx> { reported_errors: FxHashSet<(Ty<'tcx>, Span)>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, universal_region_relations: &'a UniversalRegionRelations<'tcx>, + opaque_type_values: FxHashMap>, } struct BorrowCheckContext<'a, 'tcx> { @@ -811,7 +831,8 @@ struct BorrowCheckContext<'a, 'tcx> { crate struct MirTypeckResults<'tcx> { crate constraints: MirTypeckRegionConstraints<'tcx>, - crate universal_region_relations: Rc>, + pub(in crate::borrow_check) universal_region_relations: Frozen>, + crate opaque_type_values: FxHashMap>, } /// A collection of region constraints that must be satisfied for the @@ -958,6 +979,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { borrowck_context, reported_errors: Default::default(), universal_region_relations, + opaque_type_values: FxHashMap::default(), }; checker.check_user_type_annotations(); checker @@ -1191,10 +1213,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { anon_ty={:?})", revealed_ty, anon_ty ); + + // Fast path for the common case. + if !anon_ty.has_opaque_types() { + if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) { + span_mirbug!( + self, + locations, + "eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`", + revealed_ty, + anon_ty, + terr + ); + } + return Ok(()); + } + let infcx = self.infcx; let tcx = infcx.tcx; let param_env = self.param_env; let body = self.body; + let concrete_opaque_types = &tcx.typeck_tables_of(anon_owner_def_id).concrete_opaque_types; + let mut opaque_type_values = Vec::new(); + debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id); let opaque_type_map = self.fully_perform_op( locations, @@ -1219,6 +1260,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { revealed_ty={:?}", output_ty, opaque_type_map, revealed_ty ); + // Make sure that the inferred types are well-formed. I'm + // not entirely sure this is needed (the HIR type check + // didn't do this) but it seems sensible to prevent opaque + // types hiding ill-formed types. + obligations.obligations.push(traits::Obligation::new( + ObligationCause::dummy(), + param_env, + ty::Predicate::WellFormed(revealed_ty), + )); obligations.add( infcx .at(&ObligationCause::dummy(), param_env) @@ -1226,47 +1276,76 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); for (&opaque_def_id, opaque_decl) in &opaque_type_map { - let opaque_defn_ty = tcx.type_of(opaque_def_id); - let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs); - let opaque_defn_ty = renumber::renumber_regions(infcx, &opaque_defn_ty); - let concrete_is_opaque = infcx - .resolve_vars_if_possible(&opaque_decl.concrete_ty) - .is_impl_trait(); + let resolved_ty = infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty); + let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind { + def_id == opaque_def_id + } else { + false + }; + let opaque_defn_ty = match concrete_opaque_types.get(&opaque_def_id) { + None => { + if !concrete_is_opaque { + tcx.sess.delay_span_bug( + body.span, + &format!( + "Non-defining use of {:?} with revealed type", + opaque_def_id, + ), + ); + } + continue; + } + Some(opaque_defn_ty) => opaque_defn_ty, + }; + debug!("opaque_defn_ty = {:?}", opaque_defn_ty); + let subst_opaque_defn_ty = + opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs); + let renumbered_opaque_defn_ty = + renumber::renumber_regions(infcx, &subst_opaque_defn_ty); debug!( - "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?} \ - concrete_is_opaque={}", - opaque_decl.concrete_ty, - infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty), - opaque_defn_ty, - concrete_is_opaque + "eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}", + opaque_decl.concrete_ty, resolved_ty, renumbered_opaque_defn_ty, ); - // concrete_is_opaque is `true` when we're using an opaque `impl Trait` - // type without 'revealing' it. For example, code like this: - // - // type Foo = impl Debug; - // fn foo1() -> Foo { ... } - // fn foo2() -> Foo { foo1() } - // - // In `foo2`, we're not revealing the type of `Foo` - we're - // just treating it as the opaque type. - // - // When this occurs, we do *not* want to try to equate - // the concrete type with the underlying defining type - // of the opaque type - this will always fail, since - // the defining type of an opaque type is always - // some other type (e.g. not itself) - // Essentially, none of the normal obligations apply here - - // we're just passing around some unknown opaque type, - // without actually looking at the underlying type it - // gets 'revealed' into - if !concrete_is_opaque { + // Equate concrete_ty (an inference variable) with + // the renumbered type from typeck. obligations.add( infcx .at(&ObligationCause::dummy(), param_env) - .eq(opaque_decl.concrete_ty, opaque_defn_ty)?, + .eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?, + ); + opaque_type_values.push(( + opaque_def_id, + ty::ResolvedOpaqueTy { + concrete_type: renumbered_opaque_defn_ty, + substs: opaque_decl.substs, + }, + )); + } else { + // We're using an opaque `impl Trait` type without + // 'revealing' it. For example, code like this: + // + // type Foo = impl Debug; + // fn foo1() -> Foo { ... } + // fn foo2() -> Foo { foo1() } + // + // In `foo2`, we're not revealing the type of `Foo` - we're + // just treating it as the opaque type. + // + // When this occurs, we do *not* want to try to equate + // the concrete type with the underlying defining type + // of the opaque type - this will always fail, since + // the defining type of an opaque type is always + // some other type (e.g. not itself) + // Essentially, none of the normal obligations apply here - + // we're just passing around some unknown opaque type, + // without actually looking at the underlying type it + // gets 'revealed' into + debug!( + "eq_opaque_type_and_type: non-defining use of {:?}", + opaque_def_id, ); } } @@ -1282,6 +1361,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ), )?; + self.opaque_type_values.extend(opaque_type_values); + let universal_region_relations = self.universal_region_relations; // Finally, if we instantiated the anon types successfully, we @@ -1298,6 +1379,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { infcx.constrain_opaque_type( opaque_def_id, &opaque_decl, + GenerateMemberConstraints::IfNoStaticBound, universal_region_relations, ); Ok(InferOk { value: (), obligations: vec![] }) @@ -1562,7 +1644,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); } - if let PanicInfo::BoundsCheck { ref len, ref index } = *msg { + if let AssertKind::BoundsCheck { ref len, ref index } = *msg { if len.ty(body, tcx) != tcx.types.usize { span_mirbug!(self, len, "bounds-check length non-usize {:?}", len) } @@ -1826,7 +1908,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // expressions evaluate through `as_temp` or `into` a return // slot or local, so to find all unsized rvalues it is enough // to check all temps, return slots and locals. - if let None = self.reported_errors.replace((ty, span)) { + if self.reported_errors.replace((ty, span)).is_none() { let mut diag = struct_span_err!( self.tcx().sess, span, @@ -1926,7 +2008,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { &traits::Obligation::new( ObligationCause::new( span, - self.tcx().hir().def_index_to_hir_id(self.mir_def_id.index), + self.tcx() + .hir() + .local_def_id_to_hir_id(self.mir_def_id.expect_local()), traits::ObligationCauseCode::RepeatVec(should_suggest), ), self.param_env, @@ -2512,7 +2596,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { substs: SubstsRef<'tcx>, location: Location, ) -> ty::InstantiatedPredicates<'tcx> { - if let Some(closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements { + if let Some(ref closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements + { let closure_constraints = QueryRegionConstraints { outlives: closure_region_requirements.apply_requirements(tcx, def_id, substs), diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs index edbcd715159..ebaafd40262 100644 --- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs @@ -1,10 +1,10 @@ -use rustc::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; -use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc::mir::ConstraintCategory; -use rustc::traits::query::Fallible; -use rustc::traits::DomainGoal; use rustc::ty::relate::TypeRelation; use rustc::ty::{self, Ty}; +use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; +use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin}; +use rustc_trait_selection::traits::query::Fallible; +use rustc_trait_selection::traits::DomainGoal; use crate::borrow_check::constraints::OutlivesConstraint; use crate::borrow_check::type_check::{BorrowCheckContext, Locations}; @@ -64,7 +64,7 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> { } fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> { - if let Some(_) = &mut self.borrowck_context { + if self.borrowck_context.is_some() { let origin = NLLRegionVariableOrigin::Existential { from_forall }; self.infcx.next_nll_region_var(origin) } else { diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/src/librustc_mir/borrow_check/universal_regions.rs index f6e3ca2f809..c1acd5bd9a6 100644 --- a/src/librustc_mir/borrow_check/universal_regions.rs +++ b/src/librustc_mir/borrow_check/universal_regions.rs @@ -13,7 +13,6 @@ //! just returns them for other code to use. use either::Either; -use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc::middle::lang_items; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; @@ -24,6 +23,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{BodyOwnerKind, HirId}; use rustc_index::vec::{Idx, IndexVec}; +use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin}; use std::iter; use crate::borrow_check::nll::ToRegionVid; @@ -131,6 +131,29 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0, } } + + pub fn is_fn_def(&self) -> bool { + match *self { + DefiningTy::FnDef(..) => true, + _ => false, + } + } + + pub fn is_const(&self) -> bool { + match *self { + DefiningTy::Const(..) => true, + _ => false, + } + } + + pub fn def_id(&self) -> DefId { + match *self { + DefiningTy::Closure(def_id, ..) + | DefiningTy::Generator(def_id, ..) + | DefiningTy::FnDef(def_id, ..) + | DefiningTy::Const(def_id, ..) => def_id, + } + } } #[derive(Debug)] @@ -463,7 +486,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { defining_ty, unnormalized_output_ty, unnormalized_input_tys, - yield_ty: yield_ty, + yield_ty, } } @@ -751,9 +774,9 @@ fn for_each_late_bound_region_defined_on<'tcx>( fn_def_id: DefId, mut f: impl FnMut(ty::Region<'tcx>), ) { - if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.index) { + if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) { for late_bound in late_bounds.iter() { - let hir_id = HirId { owner: fn_def_id.index, local_id: *late_bound }; + let hir_id = HirId { owner: fn_def_id.expect_local(), local_id: *late_bound }; let name = tcx.hir().name(hir_id); let region_def_id = tcx.hir().local_def_id(hir_id); let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion { diff --git a/src/librustc_mir/const_eval/error.rs b/src/librustc_mir/const_eval/error.rs index c2db3c31f85..63ad9ec8cae 100644 --- a/src/librustc_mir/const_eval/error.rs +++ b/src/librustc_mir/const_eval/error.rs @@ -1,33 +1,47 @@ use std::error::Error; use std::fmt; +use rustc::mir::AssertKind; +use rustc_span::Symbol; + use super::InterpCx; -use crate::interpret::{ConstEvalErr, InterpErrorInfo, Machine}; +use crate::interpret::{ConstEvalErr, InterpError, InterpErrorInfo, Machine}; + +/// The CTFE machine has some custom error kinds. #[derive(Clone, Debug)] -pub enum ConstEvalError { +pub enum ConstEvalErrKind { NeedsRfc(String), ConstAccessesStatic, + AssertFailure(AssertKind), + Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, } -impl<'tcx> Into> for ConstEvalError { +// The errors become `MachineStop` with plain strings when being raised. +// `ConstEvalErr` (in `librustc/mir/interpret/error.rs`) knows to +// handle these. +impl<'tcx> Into> for ConstEvalErrKind { fn into(self) -> InterpErrorInfo<'tcx> { - err_unsup!(Unsupported(self.to_string())).into() + InterpError::MachineStop(Box::new(self.to_string())).into() } } -impl fmt::Display for ConstEvalError { +impl fmt::Display for ConstEvalErrKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use self::ConstEvalError::*; + use self::ConstEvalErrKind::*; match *self { NeedsRfc(ref msg) => { write!(f, "\"{}\" needs an rfc before being allowed inside constants", msg) } ConstAccessesStatic => write!(f, "constant accesses static"), + AssertFailure(ref msg) => write!(f, "{:?}", msg), + Panic { msg, line, col, file } => { + write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col) + } } } } -impl Error for ConstEvalError {} +impl Error for ConstEvalErrKind {} /// Turn an interpreter error into something to report to the user. /// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace. diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 2e8e4dac237..ffbff00cf37 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -89,7 +89,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>( InterpCx::new( tcx.at(span), param_env, - CompileTimeInterpreter::new(), + CompileTimeInterpreter::new(*tcx.sess.const_eval_limit.get()), MemoryExtra { can_access_statics }, ) } @@ -97,7 +97,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>( pub(super) fn op_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, 'tcx>, op: OpTy<'tcx>, -) -> &'tcx ty::Const<'tcx> { +) -> ConstValue<'tcx> { // We do not have value optimizations for everything. // Only scalars and slices, since they are very common. // Note that further down we turn scalars of undefined bits back to `ByRef`. These can result @@ -144,7 +144,7 @@ pub(super) fn op_to_const<'tcx>( ConstValue::Scalar(Scalar::zst()) } }; - let val = match immediate { + match immediate { Ok(mplace) => to_const_value(mplace), // see comment on `let try_as_immediate` above Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x { @@ -166,8 +166,7 @@ pub(super) fn op_to_const<'tcx>( let len: usize = len.try_into().unwrap(); ConstValue::Slice { data, start, end: start + len } } - }; - ecx.tcx.mk_const(ty::Const { val: ty::ConstKind::Value(val), ty: op.layout.ty }) + } } fn validate_and_turn_into_const<'tcx>( @@ -187,7 +186,12 @@ fn validate_and_turn_into_const<'tcx>( if cid.promoted.is_none() { let mut ref_tracking = RefTracking::new(mplace); while let Some((mplace, path)) = ref_tracking.todo.pop() { - ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?; + ecx.const_validate_operand( + mplace.into(), + path, + &mut ref_tracking, + /*may_ref_to_static*/ is_static, + )?; } } // Now that we validated, turn this into a proper constant. @@ -195,13 +199,10 @@ fn validate_and_turn_into_const<'tcx>( // whether they become immediates. if is_static || cid.promoted.is_some() { let ptr = mplace.ptr.assert_ptr(); - Ok(tcx.mk_const(ty::Const { - val: ty::ConstKind::Value(ConstValue::ByRef { - alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), - offset: ptr.offset, - }), - ty: mplace.layout.ty, - })) + Ok(ConstValue::ByRef { + alloc: ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), + offset: ptr.offset, + }) } else { Ok(op_to_const(&ecx, mplace.into())) } @@ -230,7 +231,7 @@ pub fn const_eval_validated_provider<'tcx>( match tcx.const_eval_validated(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} - // dedupliate calls + // deduplicate calls other => return other, } } @@ -271,7 +272,7 @@ pub fn const_eval_raw_provider<'tcx>( match tcx.const_eval_raw(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} - // dedupliate calls + // deduplicate calls other => return other, } } @@ -288,7 +289,10 @@ pub fn const_eval_raw_provider<'tcx>( let cid = key.value; let def_id = cid.instance.def.def_id(); - if def_id.is_local() && tcx.typeck_tables_of(def_id).tainted_by_errors { + if def_id.is_local() + && tcx.has_typeck_tables(def_id) + && tcx.typeck_tables_of(def_id).tainted_by_errors + { return Err(ErrorHandled::Reported); } @@ -298,7 +302,7 @@ pub fn const_eval_raw_provider<'tcx>( let mut ecx = InterpCx::new( tcx.at(span), key.param_env, - CompileTimeInterpreter::new(), + CompileTimeInterpreter::new(*tcx.sess.const_eval_limit.get()), MemoryExtra { can_access_statics: is_static }, ); diff --git a/src/librustc_mir/const_eval/fn_queries.rs b/src/librustc_mir/const_eval/fn_queries.rs index 4144bbc41d2..470e4e7ed25 100644 --- a/src/librustc_mir/const_eval/fn_queries.rs +++ b/src/librustc_mir/const_eval/fn_queries.rs @@ -3,7 +3,7 @@ use rustc::ty::query::Providers; use rustc::ty::TyCtxt; use rustc_attr as attr; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_span::symbol::Symbol; use rustc_target::spec::abi::Abi; @@ -82,72 +82,96 @@ pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } } -pub fn provide(providers: &mut Providers<'_>) { - /// Const evaluability whitelist is here to check evaluability at the - /// top level beforehand. - fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - if tcx.is_closure(def_id) { - return None; - } +pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { + let parent_id = tcx.hir().get_parent_did(hir_id); + if !parent_id.is_top_level_module() { + is_const_impl_raw(tcx, parent_id.expect_local()) + } else { + false + } +} - match tcx.fn_sig(def_id).abi() { - Abi::RustIntrinsic | Abi::PlatformIntrinsic => { - Some(tcx.lookup_const_stability(def_id).is_some()) - } - _ => None, +/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether +/// said intrinsic is on the whitelist for being const callable. +fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + let hir_id = + tcx.hir().as_local_hir_id(def_id).expect("Non-local call to local provider is_const_fn"); + + let node = tcx.hir().get(hir_id); + + if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) { + whitelisted + } else if let Some(fn_like) = FnLikeNode::from_node(node) { + if fn_like.constness() == hir::Constness::Const { + return true; } - } - /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether - /// said intrinsic is on the whitelist for being const callable. - fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let hir_id = tcx - .hir() - .as_local_hir_id(def_id) - .expect("Non-local call to local provider is_const_fn"); + // If the function itself is not annotated with `const`, it may still be a `const fn` + // if it resides in a const trait impl. + is_parent_const_impl_raw(tcx, hir_id) + } else if let hir::Node::Ctor(_) = node { + true + } else { + false + } +} - let node = tcx.hir().get(hir_id); +/// Const evaluability whitelist is here to check evaluability at the +/// top level beforehand. +fn is_const_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + if tcx.is_closure(def_id) { + return None; + } - if let Some(whitelisted) = is_const_intrinsic(tcx, def_id) { - whitelisted - } else if let Some(fn_like) = FnLikeNode::from_node(node) { - fn_like.constness() == hir::Constness::Const - } else if let hir::Node::Ctor(_) = node { - true - } else { - false + match tcx.fn_sig(def_id).abi() { + Abi::RustIntrinsic | Abi::PlatformIntrinsic => { + Some(tcx.lookup_const_stability(def_id).is_some()) } + _ => None, } +} - fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - is_const_fn(tcx, def_id) - && match tcx.lookup_const_stability(def_id) { - Some(stab) => { - if cfg!(debug_assertions) && stab.promotable { - let sig = tcx.fn_sig(def_id); - assert_eq!( - sig.unsafety(), - hir::Unsafety::Normal, - "don't mark const unsafe fns as promotable", - // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682 - ); - } - stab.promotable +/// Checks whether the given item is an `impl` that has a `const` modifier. +fn is_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let node = tcx.hir().get(hir_id); + matches!( + node, + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl { constness: hir::Constness::Const, .. }, + .. + }) + ) +} + +fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + is_const_fn(tcx, def_id) + && match tcx.lookup_const_stability(def_id) { + Some(stab) => { + if cfg!(debug_assertions) && stab.promotable { + let sig = tcx.fn_sig(def_id); + assert_eq!( + sig.unsafety(), + hir::Unsafety::Normal, + "don't mark const unsafe fns as promotable", + // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682 + ); } - None => false, + stab.promotable } - } + None => false, + } +} - fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - is_const_fn(tcx, def_id) - && tcx - .lookup_const_stability(def_id) - .map(|stab| stab.allow_const_fn_ptr) - .unwrap_or(false) - } +fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + is_const_fn(tcx, def_id) + && tcx.lookup_const_stability(def_id).map(|stab| stab.allow_const_fn_ptr).unwrap_or(false) +} +pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { is_const_fn_raw, + is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, def_id.expect_local()), is_promotable_const_fn, const_fn_is_allowed_fn_ptr, ..*providers diff --git a/src/librustc_mir/const_eval/machine.rs b/src/librustc_mir/const_eval/machine.rs index 1aed91baba6..28889486c38 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/src/librustc_mir/const_eval/machine.rs @@ -1,18 +1,20 @@ use rustc::mir; use rustc::ty::layout::HasTyCtxt; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc_hir::def_id::DefId; +use rustc::ty::{self, Ty}; use std::borrow::{Borrow, Cow}; use std::collections::hash_map::Entry; +use std::convert::TryFrom; use std::hash::Hash; use rustc_data_structures::fx::FxHashMap; +use rustc::mir::AssertMessage; use rustc_span::source_map::Span; +use rustc_span::symbol::Symbol; use crate::interpret::{ - self, snapshot, AllocId, Allocation, AssertMessage, GlobalId, ImmTy, InterpCx, InterpResult, - Memory, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, + self, snapshot, AllocId, Allocation, GlobalId, ImmTy, InterpCx, InterpResult, Memory, + MemoryKind, OpTy, PlaceTy, Pointer, Scalar, }; use super::error::*; @@ -56,11 +58,34 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { self.dump_place(*dest); return Ok(true); } + + /// "Intercept" a function call to a panic-related function + /// because we have something special to do for it. + /// If this returns successfully (`Ok`), the function should just be evaluated normally. + fn hook_panic_fn( + &mut self, + span: Span, + instance: ty::Instance<'tcx>, + args: &[OpTy<'tcx>], + ) -> InterpResult<'tcx> { + let def_id = instance.def_id(); + if Some(def_id) == self.tcx.lang_items().panic_fn() + || Some(def_id) == self.tcx.lang_items().begin_panic_fn() + { + // &'static str + assert!(args.len() == 1); + + let msg_place = self.deref_operand(args[0])?; + let msg = Symbol::intern(self.read_str(msg_place)?); + let span = self.find_closest_untracked_caller_location().unwrap_or(span); + let (file, line, col) = self.location_triple_for_span(span); + Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()) + } else { + Ok(()) + } + } } -/// Number of steps until the detector even starts doing anything. -/// Also, a warning is shown to the user when this number is reached. -const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000; /// The number of steps between loop detector snapshots. /// Should be a power of two for performance reasons. const DETECTOR_SNAPSHOT_PERIOD: isize = 256; @@ -73,6 +98,8 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { /// detector period. pub(super) steps_since_detector_enabled: isize, + pub(super) is_detector_enabled: bool, + /// Extra state to detect loops. pub(super) loop_detector: snapshot::InfiniteLoopDetector<'mir, 'tcx>, } @@ -84,10 +111,14 @@ pub struct MemoryExtra { } impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { - pub(super) fn new() -> Self { + pub(super) fn new(const_eval_limit: usize) -> Self { + let steps_until_detector_enabled = + isize::try_from(const_eval_limit).unwrap_or(std::isize::MAX); + CompileTimeInterpreter { loop_detector: Default::default(), - steps_since_detector_enabled: -STEPS_UNTIL_DETECTOR_ENABLED, + steps_since_detector_enabled: -steps_until_detector_enabled, + is_detector_enabled: const_eval_limit != 0, } } } @@ -198,21 +229,20 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } } else { // Some functions we support even if they are non-const -- but avoid testing - // that for const fn! We certainly do *not* want to actually call the fn + // that for const fn! + ecx.hook_panic_fn(span, instance, args)?; + // We certainly do *not* want to actually call the fn // though, so be sure we return here. - return if ecx.hook_panic_fn(span, instance, args)? { - Ok(None) - } else { - throw_unsup_format!("calling non-const function `{}`", instance) - }; + throw_unsup_format!("calling non-const function `{}`", instance) } } // This is a const fn. Call it. Ok(Some(match ecx.load_mir(instance.def, None) { Ok(body) => *body, Err(err) => { - if let err_unsup!(NoMirFor(ref path)) = err.kind { - return Err(ConstEvalError::NeedsRfc(format!( + if let err_unsup!(NoMirFor(did)) = err.kind { + let path = ecx.tcx.def_path_str(did); + return Err(ConstEvalErrKind::NeedsRfc(format!( "calling extern function `{}`", path )) @@ -246,17 +276,17 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } // An intrinsic that we do not support let intrinsic_name = ecx.tcx.item_name(instance.def_id()); - Err(ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into()) + Err(ConstEvalErrKind::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into()) } fn assert_panic( ecx: &mut InterpCx<'mir, 'tcx, Self>, - _span: Span, msg: &AssertMessage<'tcx>, _unwind: Option, ) -> InterpResult<'tcx> { - use rustc::mir::interpret::PanicInfo::*; - Err(match msg { + use rustc::mir::AssertKind::*; + // Convert `AssertKind` to `AssertKind`. + let err = match msg { BoundsCheck { ref len, ref index } => { let len = ecx .read_immediate(ecx.eval_operand(len, None)?) @@ -268,21 +298,20 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, .expect("can't eval index") .to_scalar()? .to_machine_usize(&*ecx)?; - err_panic!(BoundsCheck { len, index }) + BoundsCheck { len, index } } - Overflow(op) => err_panic!(Overflow(*op)), - OverflowNeg => err_panic!(OverflowNeg), - DivisionByZero => err_panic!(DivisionByZero), - RemainderByZero => err_panic!(RemainderByZero), - ResumedAfterReturn(generator_kind) => err_panic!(ResumedAfterReturn(*generator_kind)), - ResumedAfterPanic(generator_kind) => err_panic!(ResumedAfterPanic(*generator_kind)), - Panic { .. } => bug!("`Panic` variant cannot occur in MIR"), - } - .into()) + Overflow(op) => Overflow(*op), + OverflowNeg => OverflowNeg, + DivisionByZero => DivisionByZero, + RemainderByZero => RemainderByZero, + ResumedAfterReturn(generator_kind) => ResumedAfterReturn(*generator_kind), + ResumedAfterPanic(generator_kind) => ResumedAfterPanic(*generator_kind), + }; + Err(ConstEvalErrKind::AssertFailure(err).into()) } fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> { - Err(ConstEvalError::NeedsRfc("pointer-to-integer cast".to_string()).into()) + Err(ConstEvalErrKind::NeedsRfc("pointer-to-integer cast".to_string()).into()) } fn binary_ptr_op( @@ -291,14 +320,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _left: ImmTy<'tcx>, _right: ImmTy<'tcx>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - Err(ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into()) - } - - fn find_foreign_static( - _tcx: TyCtxt<'tcx>, - _def_id: DefId, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { - throw_unsup!(ReadForeignStatic) + Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into()) } #[inline(always)] @@ -321,10 +343,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _ecx: &mut InterpCx<'mir, 'tcx, Self>, _dest: PlaceTy<'tcx>, ) -> InterpResult<'tcx> { - Err(ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into()) + Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into()) } fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + if !ecx.machine.is_detector_enabled { + return Ok(()); + } + { let steps = &mut ecx.machine.steps_since_detector_enabled; @@ -355,7 +381,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, if memory_extra.can_access_statics { Ok(()) } else { - Err(ConstEvalError::ConstAccessesStatic.into()) + Err(ConstEvalErrKind::ConstAccessesStatic.into()) } } } diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval/mod.rs similarity index 89% rename from src/librustc_mir/const_eval.rs rename to src/librustc_mir/const_eval/mod.rs index aad0e162935..605091d6c7d 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval/mod.rs @@ -26,7 +26,7 @@ pub(crate) fn const_field<'tcx>( variant: Option, field: mir::Field, value: &'tcx ty::Const<'tcx>, -) -> &'tcx ty::Const<'tcx> { +) -> ConstValue<'tcx> { trace!("const_field: {:?}, {:?}", field, value); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); // get the operand again @@ -43,22 +43,16 @@ pub(crate) fn const_field<'tcx>( op_to_const(&ecx, field) } -pub(crate) fn const_caller_location<'tcx>( +pub(crate) fn const_caller_location( tcx: TyCtxt<'tcx>, (file, line, col): (Symbol, u32, u32), -) -> &'tcx ty::Const<'tcx> { +) -> ConstValue<'tcx> { trace!("const_caller_location: {}:{}:{}", file, line, col); let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false); - let loc_ty = tcx.caller_location_ty(); let loc_place = ecx.alloc_caller_location(file, line, col); intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place, false).unwrap(); - let loc_const = ty::Const { - ty: loc_ty, - val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())), - }; - - tcx.mk_const(loc_const) + ConstValue::Scalar(loc_place.ptr) } // this function uses `unwrap` copiously, because an already validated constant @@ -84,7 +78,8 @@ pub(crate) fn destructure_const<'tcx>( let down = ecx.operand_downcast(op, variant).unwrap(); let fields_iter = (0..field_count).map(|i| { let field_op = ecx.operand_field(down, i).unwrap(); - op_to_const(&ecx, field_op) + let val = op_to_const(&ecx, field_op); + ty::Const::from_value(tcx, val, field_op.layout.ty) }); let fields = tcx.arena.alloc_from_iter(fields_iter); diff --git a/src/librustc_mir/dataflow/generic/cursor.rs b/src/librustc_mir/dataflow/generic/cursor.rs index 8c0ab150528..170157aca5d 100644 --- a/src/librustc_mir/dataflow/generic/cursor.rs +++ b/src/librustc_mir/dataflow/generic/cursor.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; -use rustc::mir::{self, BasicBlock, Location}; +use rustc::mir::{self, BasicBlock, Location, TerminatorKind}; use rustc_index::bit_set::BitSet; use super::{Analysis, Results}; @@ -29,14 +29,14 @@ where pos: CursorPosition, - /// When this flag is set, the cursor is pointing at a `Call` terminator whose call return - /// effect has been applied to `state`. + /// When this flag is set, the cursor is pointing at a `Call` or `Yield` terminator whose call + /// return or resume effect has been applied to `state`. /// - /// This flag helps to ensure that multiple calls to `seek_after_assume_call_returns` with the + /// This flag helps to ensure that multiple calls to `seek_after_assume_success` with the /// same target will result in exactly one invocation of `apply_call_return_effect`. It is /// sufficient to clear this only in `seek_to_block_start`, since seeking away from a /// terminator will always require a cursor reset. - call_return_effect_applied: bool, + success_effect_applied: bool, } impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R> @@ -50,7 +50,7 @@ where body, pos: CursorPosition::BlockStart(mir::START_BLOCK), state: results.borrow().entry_sets[mir::START_BLOCK].clone(), - call_return_effect_applied: false, + success_effect_applied: false, results, } } @@ -76,14 +76,14 @@ where pub fn seek_to_block_start(&mut self, block: BasicBlock) { self.state.overwrite(&self.results.borrow().entry_sets[block]); self.pos = CursorPosition::BlockStart(block); - self.call_return_effect_applied = false; + self.success_effect_applied = false; } /// Advances the cursor to hold all effects up to and including to the "before" effect of the /// statement (or terminator) at the given location. /// /// If you wish to observe the full effect of a statement or terminator, not just the "before" - /// effect, use `seek_after` or `seek_after_assume_call_returns`. + /// effect, use `seek_after` or `seek_after_assume_success`. pub fn seek_before(&mut self, target: Location) { assert!(target <= self.body.terminator_loc(target.block)); self.seek_(target, false); @@ -93,7 +93,7 @@ where /// terminators) up to and including the `target`. /// /// If the `target` is a `Call` terminator, any call return effect for that terminator will - /// **not** be observed. Use `seek_after_assume_call_returns` if you wish to observe the call + /// **not** be observed. Use `seek_after_assume_success` if you wish to observe the call /// return effect. pub fn seek_after(&mut self, target: Location) { assert!(target <= self.body.terminator_loc(target.block)); @@ -101,7 +101,7 @@ where // If we have already applied the call return effect, we are currently pointing at a `Call` // terminator. Unconditionally reset the dataflow cursor, since there is no way to "undo" // the call return effect. - if self.call_return_effect_applied { + if self.success_effect_applied { self.seek_to_block_start(target.block); } @@ -111,25 +111,25 @@ where /// Advances the cursor to hold all effects up to and including of the statement (or /// terminator) at the given location. /// - /// If the `target` is a `Call` terminator, any call return effect for that terminator will - /// be observed. Use `seek_after` if you do **not** wish to observe the call return effect. - pub fn seek_after_assume_call_returns(&mut self, target: Location) { + /// If the `target` is a `Call` or `Yield` terminator, any call return or resume effect for that + /// terminator will be observed. Use `seek_after` if you do **not** wish to observe the + /// "success" effect. + pub fn seek_after_assume_success(&mut self, target: Location) { let terminator_loc = self.body.terminator_loc(target.block); assert!(target.statement_index <= terminator_loc.statement_index); self.seek_(target, true); - if target != terminator_loc { + if target != terminator_loc || self.success_effect_applied { return; } + // Apply the effect of the "success" path of the terminator. + + self.success_effect_applied = true; let terminator = self.body.basic_blocks()[target.block].terminator(); - if let mir::TerminatorKind::Call { - destination: Some((return_place, _)), func, args, .. - } = &terminator.kind - { - if !self.call_return_effect_applied { - self.call_return_effect_applied = true; + match &terminator.kind { + TerminatorKind::Call { destination: Some((return_place, _)), func, args, .. } => { self.results.borrow().analysis.apply_call_return_effect( &mut self.state, target.block, @@ -138,6 +138,14 @@ where return_place, ); } + TerminatorKind::Yield { resume, resume_arg, .. } => { + self.results.borrow().analysis.apply_yield_resume_effect( + &mut self.state, + *resume, + resume_arg, + ); + } + _ => {} } } @@ -172,7 +180,7 @@ where self.seek_to_block_start(target.block) } - // N.B., `call_return_effect_applied` is checked in `seek_after`, not here. + // N.B., `success_effect_applied` is checked in `seek_after`, not here. _ => (), } diff --git a/src/librustc_mir/dataflow/generic/engine.rs b/src/librustc_mir/dataflow/generic/engine.rs index b81f0adc201..d32072125b3 100644 --- a/src/librustc_mir/dataflow/generic/engine.rs +++ b/src/librustc_mir/dataflow/generic/engine.rs @@ -5,13 +5,13 @@ use std::fs; use std::path::PathBuf; use rustc::mir::{self, traversal, BasicBlock, Location}; -use rustc::ty::TyCtxt; +use rustc::ty::{self, TyCtxt}; +use rustc_ast::ast; use rustc_data_structures::work_queue::WorkQueue; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_span::symbol::{sym, Symbol}; -use syntax::ast; use super::graphviz; use super::{Analysis, GenKillAnalysis, GenKillSet, Results}; @@ -104,7 +104,7 @@ where ) -> Self { let bits_per_block = analysis.bits_per_block(body); - let bottom_value_set = if A::BOTTOM_VALUE == true { + let bottom_value_set = if A::BOTTOM_VALUE { BitSet::new_filled(bits_per_block) } else { BitSet::new_empty(bits_per_block) @@ -218,15 +218,18 @@ where Goto { target } | Assert { target, cleanup: None, .. } - | Yield { resume: target, drop: None, .. } | Drop { target, location: _, unwind: None } | DropAndReplace { target, value: _, location: _, unwind: None } => { self.propagate_bits_into_entry_set_for(in_out, target, dirty_list) } - Yield { resume: target, drop: Some(drop), .. } => { + Yield { resume: target, drop, resume_arg, .. } => { + if let Some(drop) = drop { + self.propagate_bits_into_entry_set_for(in_out, drop, dirty_list); + } + + self.analysis.apply_yield_resume_effect(in_out, target, &resume_arg); self.propagate_bits_into_entry_set_for(in_out, target, dirty_list); - self.propagate_bits_into_entry_set_for(in_out, drop, dirty_list); } Assert { target, cleanup: Some(unwind), .. } @@ -238,9 +241,27 @@ where } } - SwitchInt { ref targets, .. } => { - for target in targets { - self.propagate_bits_into_entry_set_for(in_out, *target, dirty_list); + SwitchInt { ref targets, ref values, ref discr, .. } => { + let Engine { tcx, body, .. } = *self; + let enum_ = discr + .place() + .and_then(|discr| switch_on_enum_discriminant(tcx, body, bb_data, discr)); + match enum_ { + // If this is a switch on an enum discriminant, a custom effect may be applied + // along each outgoing edge. + Some((enum_place, enum_def)) => { + self.propagate_bits_into_enum_discriminant_switch_successors( + in_out, bb, enum_def, enum_place, dirty_list, &*values, &*targets, + ); + } + + // Otherwise, it's just a normal `SwitchInt`, and every successor sees the same + // exit state. + None => { + for target in targets.iter().copied() { + self.propagate_bits_into_entry_set_for(&in_out, target, dirty_list); + } + } } } @@ -287,6 +308,79 @@ where dirty_queue.insert(bb); } } + + fn propagate_bits_into_enum_discriminant_switch_successors( + &mut self, + in_out: &mut BitSet, + bb: BasicBlock, + enum_def: &'tcx ty::AdtDef, + enum_place: &mir::Place<'tcx>, + dirty_list: &mut WorkQueue, + values: &[u128], + targets: &[BasicBlock], + ) { + // MIR building adds discriminants to the `values` array in the same order as they + // are yielded by `AdtDef::discriminants`. We rely on this to match each + // discriminant in `values` to its corresponding variant in linear time. + let mut tmp = BitSet::new_empty(in_out.domain_size()); + let mut discriminants = enum_def.discriminants(self.tcx); + for (value, target) in values.iter().zip(targets.iter().copied()) { + let (variant_idx, _) = discriminants.find(|&(_, discr)| discr.val == *value).expect( + "Order of `AdtDef::discriminants` differed from that of `SwitchInt::values`", + ); + + tmp.overwrite(in_out); + self.analysis.apply_discriminant_switch_effect( + &mut tmp, + bb, + enum_place, + enum_def, + variant_idx, + ); + self.propagate_bits_into_entry_set_for(&tmp, target, dirty_list); + } + + std::mem::drop(tmp); + + // Propagate dataflow state along the "otherwise" edge. + let otherwise = targets.last().copied().unwrap(); + self.propagate_bits_into_entry_set_for(&in_out, otherwise, dirty_list); + } +} + +/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is +/// an enum discriminant. +/// +/// We expect such blocks to have a call to `discriminant` as their last statement like so: +/// _42 = discriminant(_1) +/// SwitchInt(_42, ..) +/// +/// If the basic block matches this pattern, this function returns the place corresponding to the +/// enum (`_1` in the example above) as well as the `AdtDef` of that enum. +fn switch_on_enum_discriminant( + tcx: TyCtxt<'tcx>, + body: &'mir mir::Body<'tcx>, + block: &'mir mir::BasicBlockData<'tcx>, + switch_on: &mir::Place<'tcx>, +) -> Option<(&'mir mir::Place<'tcx>, &'tcx ty::AdtDef)> { + match block.statements.last().map(|stmt| &stmt.kind) { + Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated)))) + if lhs == switch_on => + { + match &discriminated.ty(body, tcx).ty.kind { + ty::Adt(def, _) => Some((discriminated, def)), + + // `Rvalue::Discriminant` is also used to get the active yield point for a + // generator, but we do not need edge-specific effects in that case. This may + // change in the future. + ty::Generator(..) => None, + + t => bug!("`discriminant` called on unexpected type {:?}", t), + } + } + + _ => None, + } } // Graphviz @@ -354,7 +448,7 @@ impl RustcMirAttrs { let mut ret = RustcMirAttrs::default(); let rustc_mir_attrs = attrs - .into_iter() + .iter() .filter(|attr| attr.check_name(sym::rustc_mir)) .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter())); diff --git a/src/librustc_mir/dataflow/generic/graphviz.rs b/src/librustc_mir/dataflow/generic/graphviz.rs index b805b13592f..36decf7f5a9 100644 --- a/src/librustc_mir/dataflow/generic/graphviz.rs +++ b/src/librustc_mir/dataflow/generic/graphviz.rs @@ -195,6 +195,8 @@ where // C: Entry state self.bg = Background::Light; self.results.seek_to_block_start(block); + let block_entry_state = self.results.get().clone(); + self.write_row_with_full_state(w, "", "(on entry)")?; // D: Statement transfer functions @@ -213,29 +215,42 @@ where self.write_row_for_location(w, "T", &terminator_str, terminator_loc)?; // F: Exit state + + // Write the full dataflow state immediately after the terminator if it differs from the + // state at block entry. self.results.seek_after(terminator_loc); - if let mir::TerminatorKind::Call { destination: Some(_), .. } = &terminator.kind { - self.write_row_with_full_state(w, "", "(on unwind)")?; - - let num_state_columns = self.num_state_columns(); - self.write_row(w, "", "(on successful return)", |this, w, fmt| { - write!( - w, - r#""#, - colspan = num_state_columns, - fmt = fmt, - )?; - - let state_on_unwind = this.results.get().clone(); - this.results.seek_after_assume_call_returns(terminator_loc); - write_diff(w, this.results.analysis(), &state_on_unwind, this.results.get())?; - - write!(w, "") - })?; - } else { - self.write_row_with_full_state(w, "", "(on exit)")?; + if self.results.get() != &block_entry_state { + let after_terminator_name = match terminator.kind { + mir::TerminatorKind::Call { destination: Some(_), .. } => "(on unwind)", + _ => "(on exit)", + }; + + self.write_row_with_full_state(w, "", after_terminator_name)?; } + // Write any changes caused by terminator-specific effects + match terminator.kind { + mir::TerminatorKind::Call { destination: Some(_), .. } => { + let num_state_columns = self.num_state_columns(); + self.write_row(w, "", "(on successful return)", |this, w, fmt| { + write!( + w, + r#""#, + colspan = num_state_columns, + fmt = fmt, + )?; + + let state_on_unwind = this.results.get().clone(); + this.results.seek_after_assume_success(terminator_loc); + write_diff(w, this.results.analysis(), &state_on_unwind, this.results.get())?; + + write!(w, "") + })?; + } + + _ => {} + }; + write!(w, "") } @@ -589,8 +604,8 @@ fn write_diff>( Ok(()) } -const BR_LEFT: &'static str = r#"
"#; -const BR_LEFT_SPACE: &'static str = r#"
"#; +const BR_LEFT: &str = r#"
"#; +const BR_LEFT_SPACE: &str = r#"
"#; /// Line break policy that breaks at 40 characters and starts the next line with a single space. const LIMIT_30_ALIGN_1: Option = Some(LineBreak { sequence: BR_LEFT_SPACE, limit: 30 }); diff --git a/src/librustc_mir/dataflow/generic/mod.rs b/src/librustc_mir/dataflow/generic/mod.rs index ea643042c5f..fb4b7b9c5be 100644 --- a/src/librustc_mir/dataflow/generic/mod.rs +++ b/src/librustc_mir/dataflow/generic/mod.rs @@ -35,7 +35,8 @@ use std::io; use rustc::mir::{self, BasicBlock, Location}; -use rustc::ty::TyCtxt; +use rustc::ty::layout::VariantIdx; +use rustc::ty::{self, TyCtxt}; use rustc_hir::def_id::DefId; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_index::vec::{Idx, IndexVec}; @@ -74,6 +75,24 @@ where pub fn entry_set_for_block(&self, block: BasicBlock) -> &BitSet { &self.entry_sets[block] } + + pub fn visit_with( + &self, + body: &'mir mir::Body<'tcx>, + blocks: impl IntoIterator, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet>, + ) { + visit_results(body, blocks, self, vis) + } + + pub fn visit_in_rpo_with( + &self, + body: &'mir mir::Body<'tcx>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet>, + ) { + let blocks = mir::traversal::reverse_postorder(body); + visit_results(body, blocks.map(|(bb, _)| bb), self, vis) + } } /// Define the domain of a dataflow problem. @@ -172,7 +191,36 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { return_place: &mir::Place<'tcx>, ); - /// Calls the appropriate `Engine` constructor to find the fixpoint for this dataflow problem. + /// Updates the current dataflow state with the effect of resuming from a `Yield` terminator. + /// + /// This is similar to `apply_call_return_effect` in that it only takes place after the + /// generator is resumed, not when it is dropped. + /// + /// By default, no effects happen. + fn apply_yield_resume_effect( + &self, + _state: &mut BitSet, + _resume_block: BasicBlock, + _resume_place: &mir::Place<'tcx>, + ) { + } + + /// Updates the current dataflow state with the effect of taking a particular branch in a + /// `SwitchInt` terminator. + /// + /// Much like `apply_call_return_effect`, this effect is only propagated along a single + /// outgoing edge from this basic block. + fn apply_discriminant_switch_effect( + &self, + _state: &mut BitSet, + _block: BasicBlock, + _enum_place: &mir::Place<'tcx>, + _adt: &ty::AdtDef, + _variant: VariantIdx, + ) { + } + + /// Creates an `Engine` to find the fixpoint for this dataflow problem. /// /// You shouldn't need to override this outside this module, since the combination of the /// default impl and the one for all `A: GenKillAnalysis` will do the right thing. @@ -249,6 +297,26 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { args: &[mir::Operand<'tcx>], return_place: &mir::Place<'tcx>, ); + + /// See `Analysis::apply_yield_resume_effect`. + fn yield_resume_effect( + &self, + _trans: &mut BitSet, + _resume_block: BasicBlock, + _resume_place: &mir::Place<'tcx>, + ) { + } + + /// See `Analysis::apply_discriminant_switch_effect`. + fn discriminant_switch_effect( + &self, + _state: &mut impl GenKill, + _block: BasicBlock, + _enum_place: &mir::Place<'tcx>, + _adt: &ty::AdtDef, + _variant: VariantIdx, + ) { + } } impl
Analysis<'tcx> for A @@ -302,6 +370,26 @@ where self.call_return_effect(state, block, func, args, return_place); } + fn apply_yield_resume_effect( + &self, + state: &mut BitSet, + resume_block: BasicBlock, + resume_place: &mir::Place<'tcx>, + ) { + self.yield_resume_effect(state, resume_block, resume_place); + } + + fn apply_discriminant_switch_effect( + &self, + state: &mut BitSet, + block: BasicBlock, + enum_place: &mir::Place<'tcx>, + adt: &ty::AdtDef, + variant: VariantIdx, + ) { + self.discriminant_switch_effect(state, block, enum_place, adt, variant); + } + fn into_engine( self, tcx: TyCtxt<'tcx>, diff --git a/src/librustc_mir/dataflow/generic/tests.rs b/src/librustc_mir/dataflow/generic/tests.rs index 50d4bdb67f7..8f07a10e1b0 100644 --- a/src/librustc_mir/dataflow/generic/tests.rs +++ b/src/librustc_mir/dataflow/generic/tests.rs @@ -294,7 +294,7 @@ fn cursor_seek() { cursor.seek_after(call_terminator_loc); assert!(!cursor.get().contains(call_return_effect)); - cursor.seek_after_assume_call_returns(call_terminator_loc); + cursor.seek_after_assume_success(call_terminator_loc); assert!(cursor.get().contains(call_return_effect)); let every_target = || { @@ -310,7 +310,7 @@ fn cursor_seek() { BlockStart(block) => cursor.seek_to_block_start(block), Before(loc) => cursor.seek_before(loc), After(loc) => cursor.seek_after(loc), - AfterAssumeCallReturns(loc) => cursor.seek_after_assume_call_returns(loc), + AfterAssumeCallReturns(loc) => cursor.seek_after_assume_success(loc), } assert_eq!(cursor.get(), &cursor.analysis().expected_state_at_target(targ)); diff --git a/src/librustc_mir/dataflow/generic/visitor.rs b/src/librustc_mir/dataflow/generic/visitor.rs index 5bad8c61a0c..6e1513bcd1d 100644 --- a/src/librustc_mir/dataflow/generic/visitor.rs +++ b/src/librustc_mir/dataflow/generic/visitor.rs @@ -22,20 +22,20 @@ pub fn visit_results( let loc = Location { block, statement_index }; results.reconstruct_before_statement_effect(&mut state, stmt, loc); - vis.visit_statement(&mut state, stmt, loc); + vis.visit_statement(&state, stmt, loc); results.reconstruct_statement_effect(&mut state, stmt, loc); - vis.visit_statement_exit(&mut state, stmt, loc); + vis.visit_statement_exit(&state, stmt, loc); } let loc = body.terminator_loc(block); let term = block_data.terminator(); results.reconstruct_before_terminator_effect(&mut state, term, loc); - vis.visit_terminator(&mut state, term, loc); + vis.visit_terminator(&state, term, loc); results.reconstruct_terminator_effect(&mut state, term, loc); - vis.visit_terminator_exit(&mut state, term, loc); + vis.visit_terminator_exit(&state, term, loc); } } diff --git a/src/librustc_mir/dataflow/graphviz.rs b/src/librustc_mir/dataflow/graphviz.rs index 45d2b1a71f0..a9ef7ef6c52 100644 --- a/src/librustc_mir/dataflow/graphviz.rs +++ b/src/librustc_mir/dataflow/graphviz.rs @@ -72,7 +72,7 @@ pub struct Edge { fn outgoing(body: &Body<'_>, bb: BasicBlock) -> Vec { (0..body[bb].terminator().successors().count()) - .map(|index| Edge { source: bb, index: index }) + .map(|index| Edge { source: bb, index }) .collect() } diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index 63834d0ecda..95a676c0892 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -1,102 +1,274 @@ pub use super::*; -use crate::dataflow::{BitDenotation, GenKillSet}; +use crate::dataflow::generic::{AnalysisDomain, GenKill, GenKillAnalysis}; use rustc::mir::visit::Visitor; use rustc::mir::*; +use rustc::ty::{ParamEnv, TyCtxt}; +use rustc_span::DUMMY_SP; -/// This calculates if any part of a MIR local could have previously been borrowed. -/// This means that once a local has been borrowed, its bit will be set -/// from that point and onwards, until we see a StorageDead statement for the local, -/// at which points there is no memory associated with the local, so it cannot be borrowed. -/// This is used to compute which locals are live during a yield expression for -/// immovable generators. -#[derive(Copy, Clone)] -pub struct HaveBeenBorrowedLocals<'a, 'tcx> { - body: &'a Body<'tcx>, +pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals>; + +/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points +/// to a given local. +/// +/// The `K` parameter determines what kind of borrows are tracked. By default, +/// `MaybeBorrowedLocals` looks for *any* borrow of a local. If you are only interested in borrows +/// that might allow mutation, use the `MaybeMutBorrowedLocals` type alias instead. +/// +/// At present, this is used as a very limited form of alias analysis. For example, +/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for +/// immovable generators. `MaybeMutBorrowedLocals` is used during const checking to prove that a +/// local has not been mutated via indirect assignment (e.g., `*p = 42`), the side-effects of a +/// function call or inline assembly. +pub struct MaybeBorrowedLocals { + kind: K, + ignore_borrow_on_drop: bool, +} + +impl MaybeBorrowedLocals { + /// A dataflow analysis that records whether a pointer or reference exists that may alias the + /// given local. + pub fn all_borrows() -> Self { + MaybeBorrowedLocals { kind: AnyBorrow, ignore_borrow_on_drop: false } + } +} + +impl MaybeMutBorrowedLocals<'mir, 'tcx> { + /// A dataflow analysis that records whether a pointer or reference exists that may *mutably* + /// alias the given local. + /// + /// This includes `&mut` and pointers derived from an `&mut`, as well as shared borrows of + /// types with interior mutability. + pub fn mut_borrows_only( + tcx: TyCtxt<'tcx>, + body: &'mir mir::Body<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Self { + MaybeBorrowedLocals { + kind: MutBorrow { body, tcx, param_env }, + ignore_borrow_on_drop: false, + } + } } -impl<'a, 'tcx> HaveBeenBorrowedLocals<'a, 'tcx> { - pub fn new(body: &'a Body<'tcx>) -> Self { - HaveBeenBorrowedLocals { body } +impl MaybeBorrowedLocals { + /// During dataflow analysis, ignore the borrow that may occur when a place is dropped. + /// + /// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a + /// parameter. In the general case, a drop impl could launder that reference into the + /// surrounding environment through a raw pointer, thus creating a valid `*mut` pointing to the + /// dropped local. We are not yet willing to declare this particular case UB, so we must treat + /// all dropped locals as mutably borrowed for now. See discussion on [#61069]. + /// + /// In some contexts, we know that this borrow will never occur. For example, during + /// const-eval, custom drop glue cannot be run. Code that calls this should document the + /// assumptions that justify ignoring `Drop` terminators in this way. + /// + /// [#61069]: https://github.com/rust-lang/rust/pull/61069 + pub fn unsound_ignore_borrow_on_drop(self) -> Self { + MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self } } - pub fn body(&self) -> &Body<'tcx> { - self.body + fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T, K> { + TransferFunction { + kind: &self.kind, + trans, + ignore_borrow_on_drop: self.ignore_borrow_on_drop, + } } } -impl<'a, 'tcx> BitDenotation<'tcx> for HaveBeenBorrowedLocals<'a, 'tcx> { +impl AnalysisDomain<'tcx> for MaybeBorrowedLocals +where + K: BorrowAnalysisKind<'tcx>, +{ type Idx = Local; - fn name() -> &'static str { - "has_been_borrowed_locals" + + const NAME: &'static str = K::ANALYSIS_NAME; + + fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { + body.local_decls().len() + } + + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet) { + // No locals are aliased on function entry + } +} + +impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals +where + K: BorrowAnalysisKind<'tcx>, +{ + fn statement_effect( + &self, + trans: &mut impl GenKill, + statement: &mir::Statement<'tcx>, + location: Location, + ) { + self.transfer_function(trans).visit_statement(statement, location); } - fn bits_per_block(&self) -> usize { - self.body.local_decls.len() + + fn terminator_effect( + &self, + trans: &mut impl GenKill, + terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + self.transfer_function(trans).visit_terminator(terminator, location); } - fn start_block_effect(&self, _on_entry: &mut BitSet) { - // Nothing is borrowed on function entry + fn call_return_effect( + &self, + _trans: &mut impl GenKill, + _block: mir::BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + _dest_place: &mir::Place<'tcx>, + ) { } +} + +impl BottomValue for MaybeBorrowedLocals { + // bottom = unborrowed + const BOTTOM_VALUE: bool = false; +} - fn statement_effect(&self, trans: &mut GenKillSet, loc: Location) { - let stmt = &self.body[loc.block].statements[loc.statement_index]; +/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`. +struct TransferFunction<'a, T, K> { + trans: &'a mut T, + kind: &'a K, + ignore_borrow_on_drop: bool, +} - BorrowedLocalsVisitor { trans }.visit_statement(stmt, loc); +impl Visitor<'tcx> for TransferFunction<'a, T, K> +where + T: GenKill, + K: BorrowAnalysisKind<'tcx>, +{ + fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) { + self.super_statement(stmt, location); - // StorageDead invalidates all borrows and raw pointers to a local - match stmt.kind { - StatementKind::StorageDead(l) => trans.kill(l), - _ => (), + // When we reach a `StorageDead` statement, we can assume that any pointers to this memory + // are now invalid. + if let StatementKind::StorageDead(local) = stmt.kind { + self.trans.kill(local); } } - fn terminator_effect(&self, trans: &mut GenKillSet, loc: Location) { - let terminator = self.body[loc.block].terminator(); - BorrowedLocalsVisitor { trans }.visit_terminator(terminator, loc); - match &terminator.kind { - // Drop terminators borrows the location - TerminatorKind::Drop { location, .. } - | TerminatorKind::DropAndReplace { location, .. } => { - if let Some(local) = find_local(location) { - trans.gen(local); + fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); + + match rvalue { + mir::Rvalue::AddressOf(mt, borrowed_place) => { + if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, borrowed_place) { + self.trans.gen(borrowed_place.local); } } - _ => (), + + mir::Rvalue::Ref(_, kind, borrowed_place) => { + if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, borrowed_place) { + self.trans.gen(borrowed_place.local); + } + } + + mir::Rvalue::Cast(..) + | mir::Rvalue::Use(..) + | mir::Rvalue::Repeat(..) + | mir::Rvalue::Len(..) + | mir::Rvalue::BinaryOp(..) + | mir::Rvalue::CheckedBinaryOp(..) + | mir::Rvalue::NullaryOp(..) + | mir::Rvalue::UnaryOp(..) + | mir::Rvalue::Discriminant(..) + | mir::Rvalue::Aggregate(..) => {} } } - fn propagate_call_return( - &self, - _in_out: &mut BitSet, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, - _dest_place: &mir::Place<'tcx>, - ) { - // Nothing to do when a call returns successfully + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { + self.super_terminator(terminator, location); + + match terminator.kind { + mir::TerminatorKind::Drop { location: dropped_place, .. } + | mir::TerminatorKind::DropAndReplace { location: dropped_place, .. } => { + // See documentation for `unsound_ignore_borrow_on_drop` for an explanation. + if !self.ignore_borrow_on_drop { + self.trans.gen(dropped_place.local); + } + } + + TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::FalseEdges { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable + | TerminatorKind::Yield { .. } => {} + } } } -impl<'a, 'tcx> BottomValue for HaveBeenBorrowedLocals<'a, 'tcx> { - // bottom = unborrowed - const BOTTOM_VALUE: bool = false; +pub struct AnyBorrow; + +pub struct MutBorrow<'mir, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'mir Body<'tcx>, + param_env: ParamEnv<'tcx>, +} + +impl MutBorrow<'mir, 'tcx> { + /// `&` and `&raw` only allow mutation if the borrowed place is `!Freeze`. + /// + /// This assumes that it is UB to take the address of a struct field whose type is + /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of + /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will + /// have to check the type of the borrowed **local** instead of the borrowed **place** + /// below. See [rust-lang/unsafe-code-guidelines#134]. + /// + /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134 + fn shared_borrow_allows_mutation(&self, place: &Place<'tcx>) -> bool { + !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx, self.param_env, DUMMY_SP) + } } -struct BorrowedLocalsVisitor<'gk> { - trans: &'gk mut GenKillSet, +pub trait BorrowAnalysisKind<'tcx> { + const ANALYSIS_NAME: &'static str; + + fn in_address_of(&self, mt: Mutability, place: &Place<'tcx>) -> bool; + fn in_ref(&self, kind: mir::BorrowKind, place: &Place<'tcx>) -> bool; } -fn find_local(place: &Place<'_>) -> Option { - if !place.is_indirect() { Some(place.local) } else { None } +impl BorrowAnalysisKind<'tcx> for AnyBorrow { + const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals"; + + fn in_ref(&self, _: mir::BorrowKind, _: &Place<'_>) -> bool { + true + } + fn in_address_of(&self, _: Mutability, _: &Place<'_>) -> bool { + true + } } -impl<'tcx> Visitor<'tcx> for BorrowedLocalsVisitor<'_> { - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - if let Rvalue::Ref(_, _, ref place) = *rvalue { - if let Some(local) = find_local(place) { - self.trans.gen(local); +impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> { + const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals"; + + fn in_ref(&self, kind: mir::BorrowKind, place: &Place<'tcx>) -> bool { + match kind { + mir::BorrowKind::Mut { .. } => true, + mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => { + self.shared_borrow_allows_mutation(place) } } + } - self.super_rvalue(rvalue, location) + fn in_address_of(&self, mt: Mutability, place: &Place<'tcx>) -> bool { + match mt { + Mutability::Mut => true, + Mutability::Not => self.shared_borrow_allows_mutation(place), + } } } diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 74d1094f964..a7c0efd63b1 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -195,7 +195,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { .local_map .get(&place.local) .into_iter() - .flat_map(|bs| bs.into_iter()) + .flat_map(|bs| bs.iter()) .copied(); // If the borrowed place is a local with no projections, all other borrows of this diff --git a/src/librustc_mir/dataflow/impls/indirect_mutation.rs b/src/librustc_mir/dataflow/impls/indirect_mutation.rs deleted file mode 100644 index 85bf342c8a3..00000000000 --- a/src/librustc_mir/dataflow/impls/indirect_mutation.rs +++ /dev/null @@ -1,136 +0,0 @@ -use rustc::mir::visit::Visitor; -use rustc::mir::{self, Local, Location}; -use rustc::ty::{self, TyCtxt}; -use rustc_index::bit_set::BitSet; -use rustc_span::DUMMY_SP; - -use crate::dataflow::{self, GenKillSet}; - -/// Whether a borrow to a `Local` has been created that could allow that `Local` to be mutated -/// indirectly. This could either be a mutable reference (`&mut`) or a shared borrow if the type of -/// that `Local` allows interior mutability. Operations that can mutate local's indirectly include: -/// assignments through a pointer (`*p = 42`), function calls, drop terminators and inline assembly. -/// -/// If this returns false for a `Local` at a given statement (or terminator), that `Local` could -/// not possibly have been mutated indirectly prior to that statement. -#[derive(Copy, Clone)] -pub struct IndirectlyMutableLocals<'mir, 'tcx> { - body: &'mir mir::Body<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, -} - -impl<'mir, 'tcx> IndirectlyMutableLocals<'mir, 'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - IndirectlyMutableLocals { body, tcx, param_env } - } - - fn transfer_function<'a>( - &self, - trans: &'a mut GenKillSet, - ) -> TransferFunction<'a, 'mir, 'tcx> { - TransferFunction { body: self.body, tcx: self.tcx, param_env: self.param_env, trans } - } -} - -impl<'mir, 'tcx> dataflow::BitDenotation<'tcx> for IndirectlyMutableLocals<'mir, 'tcx> { - type Idx = Local; - - fn name() -> &'static str { - "mut_borrowed_locals" - } - - fn bits_per_block(&self) -> usize { - self.body.local_decls.len() - } - - fn start_block_effect(&self, _entry_set: &mut BitSet) { - // Nothing is borrowed on function entry - } - - fn statement_effect(&self, trans: &mut GenKillSet, loc: Location) { - let stmt = &self.body[loc.block].statements[loc.statement_index]; - self.transfer_function(trans).visit_statement(stmt, loc); - } - - fn terminator_effect(&self, trans: &mut GenKillSet, loc: Location) { - let terminator = self.body[loc.block].terminator(); - self.transfer_function(trans).visit_terminator(terminator, loc); - } - - fn propagate_call_return( - &self, - _in_out: &mut BitSet, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, - _dest_place: &mir::Place<'tcx>, - ) { - // Nothing to do when a call returns successfully - } -} - -impl<'mir, 'tcx> dataflow::BottomValue for IndirectlyMutableLocals<'mir, 'tcx> { - // bottom = unborrowed - const BOTTOM_VALUE: bool = false; -} - -/// A `Visitor` that defines the transfer function for `IndirectlyMutableLocals`. -struct TransferFunction<'a, 'mir, 'tcx> { - trans: &'a mut GenKillSet, - body: &'mir mir::Body<'tcx>, - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, -} - -impl<'tcx> TransferFunction<'_, '_, 'tcx> { - /// Returns `true` if this borrow would allow mutation of the `borrowed_place`. - fn borrow_allows_mutation( - &self, - kind: mir::BorrowKind, - borrowed_place: &mir::Place<'tcx>, - ) -> bool { - match kind { - mir::BorrowKind::Mut { .. } => true, - - mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => { - !borrowed_place.ty(self.body, self.tcx).ty.is_freeze( - self.tcx, - self.param_env, - DUMMY_SP, - ) - } - } - } -} - -impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> { - fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { - if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue { - if self.borrow_allows_mutation(kind, borrowed_place) { - if !borrowed_place.is_indirect() { - self.trans.gen(borrowed_place.local); - } - } - } - - self.super_rvalue(rvalue, location); - } - - fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { - // This method purposely does nothing except call `super_terminator`. It exists solely to - // document the subtleties around drop terminators. - - self.super_terminator(terminator, location); - - if let mir::TerminatorKind::Drop { location: _, .. } - | mir::TerminatorKind::DropAndReplace { location: _, .. } = &terminator.kind - { - // Although drop terminators mutably borrow the location being dropped, that borrow - // cannot live beyond the drop terminator because the dropped location is invalidated. - } - } -} diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 5b2264c2a65..87d8e9e411c 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -3,7 +3,8 @@ //! zero-sized structure. use rustc::mir::{self, Body, Location}; -use rustc::ty::TyCtxt; +use rustc::ty::layout::VariantIdx; +use rustc::ty::{self, TyCtxt}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; @@ -12,19 +13,18 @@ use super::MoveDataParamEnv; use crate::util::elaborate_drops::DropFlagState; use super::generic::{AnalysisDomain, GenKill, GenKillAnalysis}; -use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex}; -use super::{BottomValue, GenKillSet}; +use super::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; +use super::BottomValue; use super::drop_flag_effects_for_function_entry; use super::drop_flag_effects_for_location; use super::on_lookup_result_bits; +use crate::dataflow::drop_flag_effects; mod borrowed_locals; -mod indirect_mutation; mod storage_liveness; pub use self::borrowed_locals::*; -pub use self::indirect_mutation::IndirectlyMutableLocals; pub use self::storage_liveness::*; pub(super) mod borrows; @@ -338,6 +338,37 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { }, ); } + + fn discriminant_switch_effect( + &self, + trans: &mut impl GenKill, + _block: mir::BasicBlock, + enum_place: &mir::Place<'tcx>, + _adt: &ty::AdtDef, + variant: VariantIdx, + ) { + let enum_mpi = match self.move_data().rev_lookup.find(enum_place.as_ref()) { + LookupResult::Exact(mpi) => mpi, + LookupResult::Parent(_) => return, + }; + + // Kill all move paths that correspond to variants other than this one + let move_paths = &self.move_data().move_paths; + let enum_path = &move_paths[enum_mpi]; + for (mpi, variant_path) in enum_path.children(move_paths) { + trans.kill(mpi); + match variant_path.place.projection.last().unwrap() { + mir::ProjectionElem::Downcast(_, idx) if *idx == variant => continue, + _ => drop_flag_effects::on_all_children_bits( + self.tcx, + self.body, + self.move_data(), + mpi, + |mpi| trans.kill(mpi), + ), + } + } + } } impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/src/librustc_mir/dataflow/impls/storage_liveness.rs index 040c13e8210..5341d661b1d 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/src/librustc_mir/dataflow/impls/storage_liveness.rs @@ -1,47 +1,39 @@ pub use super::*; -use crate::dataflow::BitDenotation; -use crate::dataflow::HaveBeenBorrowedLocals; -use crate::dataflow::{DataflowResults, DataflowResultsCursor, DataflowResultsRefCursor}; +use crate::dataflow::generic::{self as dataflow, GenKill, Results, ResultsRefCursor}; +use crate::dataflow::BottomValue; use rustc::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc::mir::*; use std::cell::RefCell; #[derive(Copy, Clone)] -pub struct MaybeStorageLive<'a, 'tcx> { - body: &'a Body<'tcx>, -} +pub struct MaybeStorageLive; -impl<'a, 'tcx> MaybeStorageLive<'a, 'tcx> { - pub fn new(body: &'a Body<'tcx>) -> Self { - MaybeStorageLive { body } - } +impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive { + type Idx = Local; - pub fn body(&self) -> &Body<'tcx> { - self.body - } -} + const NAME: &'static str = "maybe_storage_live"; -impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> { - type Idx = Local; - fn name() -> &'static str { - "maybe_storage_live" - } - fn bits_per_block(&self) -> usize { - self.body.local_decls.len() + fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { + body.local_decls.len() } - fn start_block_effect(&self, on_entry: &mut BitSet) { + fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet) { // The resume argument is live on function entry (we don't care about // the `self` argument) - for arg in self.body.args_iter().skip(1) { + for arg in body.args_iter().skip(1) { on_entry.insert(arg); } } +} - fn statement_effect(&self, trans: &mut GenKillSet, loc: Location) { - let stmt = &self.body[loc.block].statements[loc.statement_index]; - +impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive { + fn statement_effect( + &self, + trans: &mut impl GenKill, + stmt: &mir::Statement<'tcx>, + _: Location, + ) { match stmt.kind { StatementKind::StorageLive(l) => trans.gen(l), StatementKind::StorageDead(l) => trans.kill(l), @@ -49,164 +41,239 @@ impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> { } } - fn terminator_effect(&self, _trans: &mut GenKillSet, _loc: Location) { + fn terminator_effect( + &self, + _trans: &mut impl GenKill, + _: &mir::Terminator<'tcx>, + _: Location, + ) { // Terminators have no effect } - fn propagate_call_return( + fn call_return_effect( &self, - _in_out: &mut BitSet, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, - _dest_place: &mir::Place<'tcx>, + _trans: &mut impl GenKill, + _block: BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + _return_place: &mir::Place<'tcx>, ) { // Nothing to do when a call returns successfully } } -impl<'a, 'tcx> BottomValue for MaybeStorageLive<'a, 'tcx> { +impl BottomValue for MaybeStorageLive { /// bottom = dead const BOTTOM_VALUE: bool = false; } +type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>; + /// Dataflow analysis that determines whether each local requires storage at a /// given location; i.e. whether its storage can go away without being observed. -pub struct RequiresStorage<'mir, 'tcx> { +pub struct MaybeRequiresStorage<'mir, 'tcx> { body: ReadOnlyBodyAndCache<'mir, 'tcx>, - borrowed_locals: - RefCell>>, + borrowed_locals: RefCell>, } -impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> { +impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { pub fn new( body: ReadOnlyBodyAndCache<'mir, 'tcx>, - borrowed_locals: &'mir DataflowResults<'tcx, HaveBeenBorrowedLocals<'mir, 'tcx>>, + borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>, ) -> Self { - RequiresStorage { + MaybeRequiresStorage { body, - borrowed_locals: RefCell::new(DataflowResultsCursor::new(borrowed_locals, *body)), + borrowed_locals: RefCell::new(ResultsRefCursor::new(*body, borrowed_locals)), } } - - pub fn body(&self) -> &Body<'tcx> { - &self.body - } } -impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> { +impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { type Idx = Local; - fn name() -> &'static str { - "requires_storage" - } - fn bits_per_block(&self) -> usize { - self.body.local_decls.len() + + const NAME: &'static str = "requires_storage"; + + fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { + body.local_decls.len() } - fn start_block_effect(&self, on_entry: &mut BitSet) { + fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet) { // The resume argument is live on function entry (we don't care about // the `self` argument) - for arg in self.body.args_iter().skip(1) { + for arg in body.args_iter().skip(1) { on_entry.insert(arg); } } +} - fn before_statement_effect(&self, sets: &mut GenKillSet, loc: Location) { - // If we borrow or assign to a place then it needs storage for that - // statement. - self.check_for_borrow(sets, loc); +impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { + fn before_statement_effect( + &self, + trans: &mut impl GenKill, + stmt: &mir::Statement<'tcx>, + loc: Location, + ) { + // If a place is borrowed in a statement, it needs storage for that statement. + self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc); - let stmt = &self.body[loc.block].statements[loc.statement_index]; - match stmt.kind { - StatementKind::StorageDead(l) => sets.kill(l), - StatementKind::Assign(box (ref place, _)) - | StatementKind::SetDiscriminant { box ref place, .. } => { - sets.gen(place.local); + match &stmt.kind { + StatementKind::StorageDead(l) => trans.kill(*l), + + // If a place is assigned to in a statement, it needs storage for that statement. + StatementKind::Assign(box (place, _)) + | StatementKind::SetDiscriminant { box place, .. } => { + trans.gen(place.local); } - StatementKind::InlineAsm(box InlineAsm { ref outputs, .. }) => { - for place in &**outputs { - sets.gen(place.local); + StatementKind::InlineAsm(asm) => { + for place in &*asm.outputs { + trans.gen(place.local); } } - _ => (), + + // Nothing to do for these. Match exhaustively so this fails to compile when new + // variants are added. + StatementKind::AscribeUserType(..) + | StatementKind::FakeRead(..) + | StatementKind::Nop + | StatementKind::Retag(..) + | StatementKind::StorageLive(..) => {} } } - fn statement_effect(&self, sets: &mut GenKillSet, loc: Location) { + fn statement_effect( + &self, + trans: &mut impl GenKill, + _: &mir::Statement<'tcx>, + loc: Location, + ) { // If we move from a place then only stops needing storage *after* // that statement. - self.check_for_move(sets, loc); + self.check_for_move(trans, loc); } - fn before_terminator_effect(&self, sets: &mut GenKillSet, loc: Location) { - self.check_for_borrow(sets, loc); + fn before_terminator_effect( + &self, + trans: &mut impl GenKill, + terminator: &mir::Terminator<'tcx>, + loc: Location, + ) { + // If a place is borrowed in a terminator, it needs storage for that terminator. + self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc); + + match &terminator.kind { + TerminatorKind::Call { destination: Some((place, _)), .. } => { + trans.gen(place.local); + } + + // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for + // that is that a `yield` will return from the function, and `resume_arg` is written + // only when the generator is later resumed. Unlike `Call`, this doesn't require the + // place to have storage *before* the yield, only after. + TerminatorKind::Yield { .. } => {} - if let TerminatorKind::Call { destination: Some((Place { local, .. }, _)), .. } = - self.body[loc.block].terminator().kind - { - sets.gen(local); + // Nothing to do for these. Match exhaustively so this fails to compile when new + // variants are added. + TerminatorKind::Call { destination: None, .. } + | TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::FalseEdges { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable => {} } } - fn terminator_effect(&self, sets: &mut GenKillSet, loc: Location) { - // For call terminators the destination requires storage for the call - // and after the call returns successfully, but not after a panic. - // Since `propagate_call_unwind` doesn't exist, we have to kill the - // destination here, and then gen it again in `propagate_call_return`. - if let TerminatorKind::Call { destination: Some((ref place, _)), .. } = - self.body[loc.block].terminator().kind - { - if let Some(local) = place.as_local() { - sets.kill(local); + fn terminator_effect( + &self, + trans: &mut impl GenKill, + terminator: &mir::Terminator<'tcx>, + loc: Location, + ) { + match &terminator.kind { + // For call terminators the destination requires storage for the call + // and after the call returns successfully, but not after a panic. + // Since `propagate_call_unwind` doesn't exist, we have to kill the + // destination here, and then gen it again in `call_return_effect`. + TerminatorKind::Call { destination: Some((place, _)), .. } => { + trans.kill(place.local); } + + // Nothing to do for these. Match exhaustively so this fails to compile when new + // variants are added. + TerminatorKind::Call { destination: None, .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::Abort + | TerminatorKind::Assert { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::FalseEdges { .. } + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Return + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Unreachable => {} } - self.check_for_move(sets, loc); + + self.check_for_move(trans, loc); + } + + fn call_return_effect( + &self, + trans: &mut impl GenKill, + _block: BasicBlock, + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], + return_place: &mir::Place<'tcx>, + ) { + trans.gen(return_place.local); } - fn propagate_call_return( + fn yield_resume_effect( &self, - in_out: &mut BitSet, - _call_bb: mir::BasicBlock, - _dest_bb: mir::BasicBlock, - dest_place: &mir::Place<'tcx>, + trans: &mut BitSet, + _resume_block: BasicBlock, + resume_place: &mir::Place<'tcx>, ) { - in_out.insert(dest_place.local); + trans.gen(resume_place.local); } } -impl<'mir, 'tcx> RequiresStorage<'mir, 'tcx> { +impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { /// Kill locals that are fully moved and have not been borrowed. - fn check_for_move(&self, sets: &mut GenKillSet, loc: Location) { - let mut visitor = MoveVisitor { sets, borrowed_locals: &self.borrowed_locals }; + fn check_for_move(&self, trans: &mut impl GenKill, loc: Location) { + let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals }; visitor.visit_location(self.body, loc); } - - /// Gen locals that are newly borrowed. This includes borrowing any part of - /// a local (we rely on this behavior of `HaveBeenBorrowedLocals`). - fn check_for_borrow(&self, sets: &mut GenKillSet, loc: Location) { - let mut borrowed_locals = self.borrowed_locals.borrow_mut(); - borrowed_locals.seek(loc); - borrowed_locals.each_gen_bit(|l| sets.gen(l)); - } } -impl<'mir, 'tcx> BottomValue for RequiresStorage<'mir, 'tcx> { +impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> { /// bottom = dead const BOTTOM_VALUE: bool = false; } -struct MoveVisitor<'a, 'mir, 'tcx> { - borrowed_locals: - &'a RefCell>>, - sets: &'a mut GenKillSet, +struct MoveVisitor<'a, 'mir, 'tcx, T> { + borrowed_locals: &'a RefCell>, + trans: &'a mut T, } -impl<'a, 'mir: 'a, 'tcx> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T> +where + T: GenKill, +{ fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) { if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { let mut borrowed_locals = self.borrowed_locals.borrow_mut(); - borrowed_locals.seek(loc); + borrowed_locals.seek_before(loc); if !borrowed_locals.contains(*local) { - self.sets.kill(*local); + self.trans.kill(*local); } } } diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 7cd7fc309b6..dd0f9ff75b9 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -1,32 +1,28 @@ -use rustc_ast_pretty::pprust; -use rustc_span::symbol::{sym, Symbol}; -use syntax::ast::{self, MetaItem}; - -use rustc_data_structures::work_queue::WorkQueue; -use rustc_index::bit_set::{BitSet, HybridBitSet}; -use rustc_index::vec::Idx; - use rustc::mir::traversal; use rustc::mir::{self, BasicBlock, BasicBlockData, Body, Location, Statement, Terminator}; -use rustc::session::Session; use rustc::ty::{self, TyCtxt}; +use rustc_ast::ast::{self, MetaItem}; +use rustc_ast_pretty::pprust; +use rustc_data_structures::work_queue::WorkQueue; use rustc_hir::def_id::DefId; +use rustc_index::bit_set::{BitSet, HybridBitSet}; +use rustc_index::vec::Idx; +use rustc_session::Session; +use rustc_span::symbol::{sym, Symbol}; use std::borrow::Borrow; use std::fmt; use std::io; use std::path::PathBuf; -use std::usize; pub use self::at_location::{FlowAtLocation, FlowsAtLocation}; pub(crate) use self::drop_flag_effects::*; pub use self::impls::borrows::Borrows; pub use self::impls::DefinitelyInitializedPlaces; pub use self::impls::EverInitializedPlaces; -pub use self::impls::HaveBeenBorrowedLocals; -pub use self::impls::IndirectlyMutableLocals; +pub use self::impls::{MaybeBorrowedLocals, MaybeMutBorrowedLocals}; pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; -pub use self::impls::{MaybeStorageLive, RequiresStorage}; +pub use self::impls::{MaybeRequiresStorage, MaybeStorageLive}; use self::move_paths::MoveData; @@ -690,11 +686,7 @@ pub trait BottomValue { /// 3. Override `join` to do the opposite from what it's doing now. #[inline] fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { - if Self::BOTTOM_VALUE == false { - inout_set.union(in_set) - } else { - inout_set.intersect(in_set) - } + if !Self::BOTTOM_VALUE { inout_set.union(in_set) } else { inout_set.intersect(in_set) } } } @@ -822,7 +814,7 @@ where let bits_per_block = denotation.bits_per_block(); let num_blocks = body.basic_blocks().len(); - let on_entry = if D::BOTTOM_VALUE == true { + let on_entry = if D::BOTTOM_VALUE { vec![BitSet::new_filled(bits_per_block); num_blocks] } else { vec![BitSet::new_empty(bits_per_block); num_blocks] diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 6f8caca5e21..7c449ad1197 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -381,9 +381,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } TerminatorKind::Yield { ref value, resume_arg: ref place, .. } => { + self.gather_operand(value); self.create_move_path(place); self.gather_init(place.as_ref(), InitKind::Deep); - self.gather_operand(value); } TerminatorKind::Drop { ref location, target: _, unwind: _ } => { @@ -474,7 +474,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } fn record_move(&mut self, place: &Place<'tcx>, path: MovePathIndex) { - let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc }); + let move_out = self.builder.data.moves.push(MoveOut { path, source: self.loc }); debug!( "gather_move({:?}, {:?}): adding move {:?} of {:?}", self.loc, place, move_out, path @@ -483,7 +483,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { self.builder.data.loc_map[self.loc].push(move_out); } - fn gather_init(&mut self, place: PlaceRef<'cx, 'tcx>, kind: InitKind) { + fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) { debug!("gather_init({:?}, {:?})", self.loc, place); let mut place = place; diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 614a2761643..593952bfa7c 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -58,19 +58,32 @@ pub struct MovePath<'tcx> { } impl<'tcx> MovePath<'tcx> { - pub fn parents( + /// Returns an iterator over the parents of `self`. + pub fn parents<'a>( &self, - move_paths: &IndexVec>, - ) -> Vec { - let mut parents = Vec::new(); - - let mut curr_parent = self.parent; - while let Some(parent_mpi) = curr_parent { - parents.push(parent_mpi); - curr_parent = move_paths[parent_mpi].parent; + move_paths: &'a IndexVec>, + ) -> impl 'a + Iterator)> { + let first = self.parent.map(|mpi| (mpi, &move_paths[mpi])); + MovePathLinearIter { + next: first, + fetch_next: move |_, parent: &MovePath<'_>| { + parent.parent.map(|mpi| (mpi, &move_paths[mpi])) + }, } + } - parents + /// Returns an iterator over the immediate children of `self`. + pub fn children<'a>( + &self, + move_paths: &'a IndexVec>, + ) -> impl 'a + Iterator)> { + let first = self.first_child.map(|mpi| (mpi, &move_paths[mpi])); + MovePathLinearIter { + next: first, + fetch_next: move |_, child: &MovePath<'_>| { + child.next_sibling.map(|mpi| (mpi, &move_paths[mpi])) + }, + } } /// Finds the closest descendant of `self` for which `f` returns `true` using a breadth-first @@ -131,6 +144,25 @@ impl<'tcx> fmt::Display for MovePath<'tcx> { } } +#[allow(unused)] +struct MovePathLinearIter<'a, 'tcx, F> { + next: Option<(MovePathIndex, &'a MovePath<'tcx>)>, + fetch_next: F, +} + +impl<'a, 'tcx, F> Iterator for MovePathLinearIter<'a, 'tcx, F> +where + F: FnMut(MovePathIndex, &'a MovePath<'tcx>) -> Option<(MovePathIndex, &'a MovePath<'tcx>)>, +{ + type Item = (MovePathIndex, &'a MovePath<'tcx>); + + fn next(&mut self) -> Option { + let ret = self.next.take()?; + self.next = (self.fetch_next)(ret.0, ret.1); + Some(ret) + } +} + #[derive(Debug)] pub struct MoveData<'tcx> { pub move_paths: IndexVec>, @@ -280,7 +312,7 @@ impl MovePathLookup { // alternative will *not* create a MovePath on the fly for an // unknown place, but will rather return the nearest available // parent. - pub fn find(&self, place: PlaceRef<'_, '_>) -> LookupResult { + pub fn find(&self, place: PlaceRef<'_>) -> LookupResult { let mut result = self.locals[place.local]; for elem in place.projection.iter() { diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 9461a066902..3cbb0667ff3 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -1,8 +1,8 @@ use rustc::ty::adjustment::PointerCast; use rustc::ty::layout::{self, Size, TyLayout}; use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable}; +use rustc_ast::ast::FloatTy; use rustc_span::symbol::sym; -use syntax::ast::FloatTy; use rustc::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc::mir::CastKind; @@ -202,7 +202,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Char => { // `u8` to `char` cast - debug_assert_eq!(v as u8 as u128, v); + assert_eq!(v as u8 as u128, v); Ok(Scalar::from_uint(v, Size::from_bytes(4))) } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 206d3d15673..481719bfa8e 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -21,7 +21,7 @@ use rustc_span::source_map::{self, Span, DUMMY_SP}; use super::{ Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy, - ScalarMaybeUndef, StackPopInfo, + ScalarMaybeUndef, StackPopJump, }; pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { @@ -98,10 +98,10 @@ pub enum StackPopCleanup { /// Jump to the next block in the caller, or cause UB if None (that's a function /// that may never return). Also store layout of return place so /// we can validate it at that layout. - /// `ret` stores the block we jump to on a normal return, while 'unwind' - /// stores the block used for cleanup during unwinding + /// `ret` stores the block we jump to on a normal return, while `unwind` + /// stores the block used for cleanup during unwinding. Goto { ret: Option, unwind: Option }, - /// Just do nohing: Used by Main and for the box_alloc hook in miri. + /// Just do nothing: Used by Main and for the `box_alloc` hook in miri. /// `cleanup` says whether locals are deallocated. Static computation /// wants them leaked to intern what they need (and just throw away /// the entire `ecx` when it is done). @@ -138,7 +138,7 @@ pub enum LocalValue { impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { pub fn access(&self) -> InterpResult<'tcx, Operand> { match self.value { - LocalValue::Dead => throw_unsup!(DeadLocal), + LocalValue::Dead => throw_ub!(DeadLocal), LocalValue::Uninitialized => { bug!("The type checker should prevent reading from a never-written local") } @@ -152,7 +152,7 @@ impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { &mut self, ) -> InterpResult<'tcx, Result<&mut LocalValue, MemPlace>> { match self.value { - LocalValue::Dead => throw_unsup!(DeadLocal), + LocalValue::Dead => throw_ub!(DeadLocal), LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)), ref mut local @ LocalValue::Live(Operand::Immediate(_)) | ref mut local @ LocalValue::Uninitialized => Ok(Ok(local)), @@ -264,7 +264,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline(always)] pub fn cur_frame(&self) -> usize { - assert!(self.stack.len() > 0); + assert!(!self.stack.is_empty()); self.stack.len() - 1 } @@ -326,7 +326,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if self.tcx.is_mir_available(did) { Ok(self.tcx.optimized_mir(did).unwrap_read_only()) } else { - throw_unsup!(NoMirFor(self.tcx.def_path_str(def_id))) + throw_unsup!(NoMirFor(def_id)) } } _ => Ok(self.tcx.instance_mir(instance)), @@ -457,10 +457,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Check if this brought us over the size limit. if size.bytes() >= self.tcx.data_layout().obj_size_bound() { - throw_ub_format!( - "wide pointer metadata contains invalid information: \ - total size is bigger than largest supported object" - ); + throw_ub!(InvalidMeta("total size is bigger than largest supported object")); } Ok(Some((size, align))) } @@ -476,10 +473,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Make sure the slice is not too big. let size = elem.size.checked_mul(len, &*self.tcx).ok_or_else(|| { - err_ub_format!( - "invalid slice: \ - total size is bigger than largest supported object" - ) + err_ub!(InvalidMeta("slice is bigger than largest supported object")) })?; Ok(Some((size, elem.align.abi))) } @@ -505,7 +499,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return_place: Option>, return_to_block: StackPopCleanup, ) -> InterpResult<'tcx> { - if self.stack.len() > 0 { + if !self.stack.is_empty() { info!("PAUSING({}) {}", self.cur_frame(), self.frame().instance); } ::log_settings::settings().indentation += 1; @@ -629,23 +623,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ::log_settings::settings().indentation -= 1; let frame = self.stack.pop().expect("tried to pop a stack frame, but there were none"); - let stack_pop_info = M::stack_pop(self, frame.extra, unwinding)?; - if let (false, StackPopInfo::StopUnwinding) = (unwinding, stack_pop_info) { - bug!("Attempted to stop unwinding while there is no unwinding!"); - } // Now where do we jump next? - // Determine if we leave this function normally or via unwinding. - let cur_unwinding = - if let StackPopInfo::StopUnwinding = stack_pop_info { false } else { unwinding }; - // Usually we want to clean up (deallocate locals), but in a few rare cases we don't. // In that case, we return early. We also avoid validation in that case, // because this is CTFE and the final value will be thoroughly validated anyway. let (cleanup, next_block) = match frame.return_to_block { StackPopCleanup::Goto { ret, unwind } => { - (true, Some(if cur_unwinding { unwind } else { ret })) + (true, Some(if unwinding { unwind } else { ret })) } StackPopCleanup::None { cleanup, .. } => (cleanup, None), }; @@ -653,7 +639,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if !cleanup { assert!(self.stack.is_empty(), "only the topmost frame should ever be leaked"); assert!(next_block.is_none(), "tried to skip cleanup when we have a next block!"); - // Leak the locals, skip validation. + assert!(!unwinding, "tried to skip cleanup during unwinding"); + // Leak the locals, skip validation, skip machine hook. return Ok(()); } @@ -662,15 +649,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.deallocate_local(local.value)?; } - trace!( - "StackPopCleanup: {:?} StackPopInfo: {:?} cur_unwinding = {:?}", - frame.return_to_block, - stack_pop_info, - cur_unwinding - ); - if cur_unwinding { + if M::stack_pop(self, frame.extra, unwinding)? == StackPopJump::NoJump { + // The hook already did everything. + // We want to skip the `info!` below, hence early return. + return Ok(()); + } + // Normal return. + if unwinding { // Follow the unwind edge. - let unwind = next_block.expect("Encounted StackPopCleanup::None when unwinding!"); + let unwind = next_block.expect("Encountered StackPopCleanup::None when unwinding!"); self.unwind_to_block(unwind); } else { // Follow the normal return edge. @@ -685,7 +672,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // invariant -- that is, unless a function somehow has a ptr to // its return place... but the way MIR is currently generated, the // return place is always a local and then this cannot happen. - self.validate_operand(self.place_to_op(return_place)?, vec![], None)?; + self.validate_operand(self.place_to_op(return_place)?)?; } } else { // Uh, that shouldn't happen... the function did not intend to return @@ -698,12 +685,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - if self.stack.len() > 0 { + if !self.stack.is_empty() { info!( "CONTINUING({}) {} (unwinding = {})", self.cur_frame(), self.frame().instance, - cur_unwinding + unwinding ); } @@ -756,6 +743,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub(super) fn const_eval( &self, gid: GlobalId<'tcx>, + ty: Ty<'tcx>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics // and thus don't care about the parameter environment. While we could just use @@ -767,17 +755,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.param_env }; - let val = if let Some(promoted) = gid.promoted { - self.tcx.const_eval_promoted(param_env, gid.instance, promoted)? - } else { - self.tcx.const_eval_instance(param_env, gid.instance, Some(self.tcx.span))? - }; + let val = self.tcx.const_eval_global_id(param_env, gid, Some(self.tcx.span))?; // Even though `ecx.const_eval` is called from `eval_const_to_op` we can never have a // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not // return `ConstValue::Unevaluated`, which is the only way that `eval_const_to_op` will call // `ecx.const_eval`. - self.eval_const_to_op(val, None) + let const_ = ty::Const { val: ty::ConstKind::Value(val), ty }; + self.eval_const_to_op(&const_, None) } pub fn const_eval_raw( diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 9fea82d78c9..90b8a493299 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -9,7 +9,7 @@ use rustc::ty::{self, Ty}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; -use syntax::ast::Mutability; +use rustc_ast::ast::Mutability; use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, Scalar, ValueVisitor}; @@ -187,7 +187,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx self.walk_aggregate(mplace, fields) } - fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> { + fn visit_value(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> { // Handle Reference types, as these are the only relocations supported by const eval. // Raw pointers (and boxes) are handled by the `leftover_relocations` logic. let ty = mplace.layout.ty; @@ -263,8 +263,11 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx None => self.ref_tracking.track((mplace, mutability, mode), || ()), } } + Ok(()) + } else { + // Not a reference -- proceed recursively. + self.walk_value(mplace) } - Ok(()) } } @@ -324,7 +327,7 @@ pub fn intern_const_alloc_recursive>( if let Err(error) = interned { // This can happen when e.g. the tag of an enum is not a valid discriminant. We do have // to read enum discriminants in order to find references in enum variant fields. - if let err_unsup!(ValidationFailure(_)) = error.kind { + if let err_ub!(ValidationFailure(_)) = error.kind { let err = crate::const_eval::error_to_const_error(&ecx, error); match err.struct_error( ecx.tcx, @@ -387,7 +390,7 @@ pub fn intern_const_alloc_recursive>( } } else if ecx.memory.dead_alloc_map.contains_key(&alloc_id) { // dangling pointer - throw_unsup!(ValidationFailure("encountered dangling pointer in final constant".into())) + throw_ub_format!("encountered dangling pointer in final constant") } else if ecx.tcx.alloc_map.lock().get(alloc_id).is_none() { // We have hit an `AllocId` that is neither in local or global memory and isn't marked // as dangling by local memory. diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index f85da760ada..03aedad0d98 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -48,22 +48,15 @@ crate fn eval_nullary_intrinsic<'tcx>( param_env: ty::ParamEnv<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, -) -> InterpResult<'tcx, &'tcx ty::Const<'tcx>> { +) -> InterpResult<'tcx, ConstValue<'tcx>> { let tp_ty = substs.type_at(0); let name = tcx.item_name(def_id); Ok(match name { sym::type_name => { let alloc = type_name::alloc_type_name(tcx, tp_ty); - tcx.mk_const(ty::Const { - val: ty::ConstKind::Value(ConstValue::Slice { - data: alloc, - start: 0, - end: alloc.len(), - }), - ty: tcx.mk_static_str(), - }) + ConstValue::Slice { data: alloc, start: 0, end: alloc.len() } } - sym::needs_drop => ty::Const::from_bool(tcx, tp_ty.needs_drop(tcx, param_env)), + sym::needs_drop => ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)), sym::size_of | sym::min_align_of | sym::pref_align_of => { let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?; let n = match name { @@ -72,11 +65,9 @@ crate fn eval_nullary_intrinsic<'tcx>( sym::size_of => layout.size.bytes(), _ => bug!(), }; - ty::Const::from_usize(tcx, n) - } - sym::type_id => { - ty::Const::from_bits(tcx, tcx.type_id_hash(tp_ty).into(), param_env.and(tcx.types.u64)) + ConstValue::from_machine_usize(n, &tcx) } + sym::type_id => ConstValue::from_u64(tcx.type_id_hash(tp_ty)), other => bug!("`{}` is not a zero arg intrinsic", other), }) } @@ -93,14 +84,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let substs = instance.substs; let intrinsic_name = self.tcx.item_name(instance.def_id()); - // We currently do not handle any intrinsics that are *allowed* to diverge, - // but `transmute` could lack a return place in case of UB. + // First handle intrinsics without return place. let (dest, ret) = match ret { - Some(p) => p, None => match intrinsic_name { - sym::transmute => throw_ub!(Unreachable), + sym::transmute => throw_ub_format!("transmuting to uninhabited type"), + sym::abort => M::abort(self)?, + // Unsupported diverging intrinsic. _ => return Ok(false), }, + Some(p) => p, }; // Keep the patterns in this match ordered the same as the list in @@ -119,7 +111,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | sym::type_id | sym::type_name => { let gid = GlobalId { instance, promoted: None }; - let val = self.const_eval(gid)?; + let ty = match intrinsic_name { + sym::min_align_of | sym::pref_align_of | sym::size_of => self.tcx.types.usize, + sym::needs_drop => self.tcx.types.bool, + sym::type_id => self.tcx.types.u64, + sym::type_name => self.tcx.mk_static_str(), + _ => span_bug!(span, "Already checked for nullary intrinsics"), + }; + let val = self.const_eval(gid, ty)?; self.copy_op(val, dest)?; } @@ -136,7 +135,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let bits = self.force_bits(val, layout_of.size)?; let kind = match layout_of.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => throw_unsup!(TypeNotPrimitive(ty)), + _ => bug!("{} called on invalid type {:?}", intrinsic_name, ty), }; let (nonzero, intrinsic_name) = match intrinsic_name { sym::cttz_nonzero => (true, sym::cttz), @@ -205,7 +204,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if is_add { // max unsigned Scalar::from_uint( - u128::max_value() >> (128 - num_bits), + u128::MAX >> (128 - num_bits), Size::from_bits(num_bits), ) } else { @@ -218,6 +217,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; self.write_scalar(val, dest)?; } + sym::discriminant_value => { + let place = self.deref_operand(args[0])?; + let discr_val = self.read_discriminant(place.into())?.0; + self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; + } sym::unchecked_shl | sym::unchecked_shr | sym::unchecked_add @@ -242,9 +246,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = self.layout_of(substs.type_at(0))?; let r_val = self.force_bits(r.to_scalar()?, layout.size)?; if let sym::unchecked_shl | sym::unchecked_shr = intrinsic_name { - throw_ub_format!("Overflowing shift by {} in `{}`", r_val, intrinsic_name); + throw_ub_format!("overflowing shift by {} in `{}`", r_val, intrinsic_name); } else { - throw_ub_format!("Overflow executing `{}`", intrinsic_name); + throw_ub_format!("overflow executing `{}`", intrinsic_name); } } self.write_scalar(val, dest)?; @@ -376,32 +380,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(true) } - /// "Intercept" a function call to a panic-related function - /// because we have something special to do for it. - /// Returns `true` if an intercept happened. - pub fn hook_panic_fn( - &mut self, - span: Span, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, M::PointerTag>], - ) -> InterpResult<'tcx, bool> { - let def_id = instance.def_id(); - if Some(def_id) == self.tcx.lang_items().panic_fn() - || Some(def_id) == self.tcx.lang_items().begin_panic_fn() - { - // &'static str - assert!(args.len() == 1); - - let msg_place = self.deref_operand(args[0])?; - let msg = Symbol::intern(self.read_str(msg_place)?); - let span = self.find_closest_untracked_caller_location().unwrap_or(span); - let (file, line, col) = self.location_triple_for_span(span); - throw_panic!(Panic { msg, file, line, col }) - } else { - return Ok(false); - } - } - pub fn exact_div( &mut self, a: ImmTy<'tcx, M::PointerTag>, @@ -409,10 +387,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { dest: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { // Performs an exact division, resulting in undefined behavior where - // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1`. - // First, check x % y != 0. - if self.binary_op(BinOp::Rem, a, b)?.to_bits()? != 0 { - // Then, check if `b` is -1, which is the "min_value / -1" case. + // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`. + // First, check x % y != 0 (or if that computation overflows). + let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, a, b)?; + if overflow || res.assert_bits(a.layout.size) != 0 { + // Then, check if `b` is -1, which is the "MIN / -1" case. let minus1 = Scalar::from_int(-1, dest.layout.size); let b_scalar = b.to_scalar().unwrap(); if b_scalar == minus1 { @@ -421,6 +400,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { throw_ub_format!("exact_div: {} cannot be divided by {} without remainder", a, b,) } } + // `Rem` says this is all right, so we can let `Div` do its job. self.binop_ignore_overflow(BinOp::Div, a, b, dest) } } diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs index 0525108d2d1..566601f0cae 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -54,12 +54,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { location } - pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::PointerTag> { - let (file, line, column) = self.location_triple_for_span(span); - self.alloc_caller_location(file, line, column) - } - - pub(super) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { + crate fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); ( @@ -68,4 +63,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { caller.col_display as u32 + 1, ) } + + pub fn alloc_caller_location_for_span(&mut self, span: Span) -> MPlaceTy<'tcx, M::PointerTag> { + let (file, line, column) = self.location_triple_for_span(span); + self.alloc_caller_location(file, line, column) + } } diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs index cd8bf7085d1..677dc697735 100644 --- a/src/librustc_mir/interpret/intrinsics/type_name.rs +++ b/src/librustc_mir/interpret/intrinsics/type_name.rs @@ -157,6 +157,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { } } } + impl PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool { false diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 3309e9b9b62..c9d32f62400 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -6,28 +6,27 @@ use std::borrow::{Borrow, Cow}; use std::hash::Hash; use rustc::mir; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc_hir::def_id::DefId; +use rustc::ty::{self, Ty}; use rustc_span::Span; use super::{ - AllocId, Allocation, AllocationExtra, AssertMessage, Frame, ImmTy, InterpCx, InterpResult, - Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar, + AllocId, Allocation, AllocationExtra, Frame, ImmTy, InterpCx, InterpResult, Memory, MemoryKind, + OpTy, Operand, PlaceTy, Pointer, Scalar, }; /// Data returned by Machine::stack_pop, /// to provide further control over the popping of the stack frame #[derive(Eq, PartialEq, Debug, Copy, Clone)] -pub enum StackPopInfo { +pub enum StackPopJump { /// Indicates that no special handling should be /// done - we'll either return normally or unwind /// based on the terminator for the function /// we're leaving. Normal, - /// Indicates that we should stop unwinding, - /// as we've reached a catch frame - StopUnwinding, + /// Indicates that we should *not* jump to the return/unwind address, as the callback already + /// took care of everything. + NoJump, } /// Whether this kind of memory is allowed to leak @@ -123,10 +122,6 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether to enforce the validity invariant fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; - /// Called before a basic block terminator is executed. - /// You can use this to detect endlessly running programs. - fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>; - /// Entry point to all function calls. /// /// Returns either the mir to use for the call, or `None` if execution should @@ -170,22 +165,14 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Called to evaluate `Assert` MIR terminators that trigger a panic. fn assert_panic( ecx: &mut InterpCx<'mir, 'tcx, Self>, - span: Span, - msg: &AssertMessage<'tcx>, + msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx>; - /// Called for read access to a foreign static item. - /// - /// This will only be called once per static and machine; the result is cached in - /// the machine memory. (This relies on `AllocMap::get_or` being able to add the - /// owned allocation to the map even when the map is shared.) - /// - /// This allocation will then be fed to `tag_allocation` to initialize the "extra" state. - fn find_foreign_static( - tcx: TyCtxt<'tcx>, - def_id: DefId, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>>; + /// Called to evaluate `Abort` MIR terminator. + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> { + throw_unsup_format!("aborting execution is not supported"); + } /// Called for all binary operations where the LHS has pointer type. /// @@ -204,6 +191,7 @@ pub trait Machine<'mir, 'tcx>: Sized { ) -> InterpResult<'tcx>; /// Called to read the specified `local` from the `frame`. + #[inline] fn access_local( _ecx: &InterpCx<'mir, 'tcx, Self>, frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, @@ -212,7 +200,15 @@ pub trait Machine<'mir, 'tcx>: Sized { frame.locals[local].access() } + /// Called before a basic block terminator is executed. + /// You can use this to detect endlessly running programs. + #[inline] + fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + Ok(()) + } + /// Called before a `Static` value is accessed. + #[inline] fn before_access_static( _memory_extra: &Self::MemoryExtra, _allocation: &Allocation, @@ -220,11 +216,22 @@ pub trait Machine<'mir, 'tcx>: Sized { Ok(()) } + /// Called for *every* memory access to determine the real ID of the given allocation. + /// This provides a way for the machine to "redirect" certain allocations as it sees fit. + /// + /// This is used by Miri to redirect extern statics to real allocations. + /// + /// This function must be idempotent. + #[inline] + fn canonical_alloc_id(_mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { + id + } + /// Called to initialize the "extra" state of an allocation and make the pointers /// it contains (in relocations) tagged. The way we construct allocations is /// to always first construct it without extra and then add the extra. /// This keeps uniform code paths for handling both allocations created by CTFE - /// for statics, and allocations ceated by Miri during evaluation. + /// for statics, and allocations created by Miri during evaluation. /// /// `kind` is the kind of the allocation being tagged; it can be `None` when /// it's a static and `STATIC_KIND` is `None`. @@ -247,6 +254,8 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Return the "base" tag for the given *static* allocation: the one that is used for direct /// accesses to this static/const/fn allocation. If `id` is not a static allocation, /// this will return an unusable tag (i.e., accesses will be UB)! + /// + /// Expects `id` to be already canonical, if needed. fn tag_static_base_pointer(memory_extra: &Self::MemoryExtra, id: AllocId) -> Self::PointerTag; /// Executes a retagging operation @@ -259,7 +268,7 @@ pub trait Machine<'mir, 'tcx>: Sized { Ok(()) } - /// Called immediately before a new stack frame got pushed + /// Called immediately before a new stack frame got pushed. fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, Self::FrameExtra>; /// Called immediately after a stack frame gets popped @@ -267,9 +276,9 @@ pub trait Machine<'mir, 'tcx>: Sized { _ecx: &mut InterpCx<'mir, 'tcx, Self>, _extra: Self::FrameExtra, _unwinding: bool, - ) -> InterpResult<'tcx, StackPopInfo> { + ) -> InterpResult<'tcx, StackPopJump> { // By default, we do not support unwinding from panics - Ok(StackPopInfo::Normal) + Ok(StackPopJump::Normal) } fn int_to_ptr( @@ -277,8 +286,10 @@ pub trait Machine<'mir, 'tcx>: Sized { int: u64, ) -> InterpResult<'tcx, Pointer> { Err((if int == 0 { - err_unsup!(InvalidNullPointerUsage) + // This is UB, seriously. + err_ub!(InvalidIntPointerUsage(0)) } else { + // This is just something we cannot support during const-eval. err_unsup!(ReadBytesAsPointer) }) .into()) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 0bcdf9ae3c1..5b2cd89a122 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -14,7 +14,7 @@ use rustc::ty::layout::{Align, HasDataLayout, Size, TargetDataLayout}; use rustc::ty::{self, query::TyCtxtAt, Instance, ParamEnv}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use syntax::ast::Mutability; +use rustc_ast::ast::Mutability; use super::{ AllocId, AllocMap, Allocation, AllocationExtra, CheckInAllocMsg, ErrorHandled, GlobalAlloc, @@ -150,7 +150,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { /// through a pointer that was created by the program. #[inline] pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer { - ptr.with_tag(M::tag_static_base_pointer(&self.extra, ptr.alloc_id)) + let id = M::canonical_alloc_id(self, ptr.alloc_id); + ptr.with_tag(M::tag_static_base_pointer(&self.extra, id)) } pub fn create_fn_alloc( @@ -214,7 +215,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { kind: MemoryKind, ) -> InterpResult<'tcx, Pointer> { if ptr.offset.bytes() != 0 { - throw_unsup!(ReallocateNonBasePtr) + throw_ub_format!( + "reallocating {:?} which does not point to the beginning of an object", + ptr + ); } // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc". @@ -250,7 +254,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { trace!("deallocating: {}", ptr.alloc_id); if ptr.offset.bytes() != 0 { - throw_unsup!(DeallocateNonBasePtr) + throw_ub_format!( + "deallocating {:?} which does not point to the beginning of an object", + ptr + ); } let (alloc_kind, mut alloc) = match self.alloc_map.remove(&ptr.alloc_id) { @@ -258,29 +265,32 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { None => { // Deallocating static memory -- always an error return Err(match self.tcx.alloc_map.lock().get(ptr.alloc_id) { - Some(GlobalAlloc::Function(..)) => err_unsup!(DeallocatedWrongMemoryKind( - "function".to_string(), - format!("{:?}", kind), - )), - Some(GlobalAlloc::Static(..)) | Some(GlobalAlloc::Memory(..)) => err_unsup!( - DeallocatedWrongMemoryKind("static".to_string(), format!("{:?}", kind)) - ), - None => err_unsup!(DoubleFree), + Some(GlobalAlloc::Function(..)) => err_ub_format!("deallocating a function"), + Some(GlobalAlloc::Static(..)) | Some(GlobalAlloc::Memory(..)) => { + err_ub_format!("deallocating static memory") + } + None => err_ub!(PointerUseAfterFree(ptr.alloc_id)), } .into()); } }; if alloc_kind != kind { - throw_unsup!(DeallocatedWrongMemoryKind( - format!("{:?}", alloc_kind), - format!("{:?}", kind), - )) + throw_ub_format!( + "deallocating `{:?}` memory using `{:?}` deallocation operation", + alloc_kind, + kind + ); } if let Some((size, align)) = old_size_and_align { if size != alloc.size || align != alloc.align { - let bytes = alloc.size; - throw_unsup!(IncorrectAllocationInformation(size, bytes, align, alloc.align)) + throw_ub_format!( + "incorrect layout on deallocation: allocation has size {} and alignment {}, but gave size {} and alignment {}", + alloc.size.bytes(), + alloc.align.bytes(), + size.bytes(), + align.bytes(), + ) } } @@ -337,7 +347,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } else { // The biggest power of two through which `offset` is divisible. let offset_pow2 = 1 << offset.trailing_zeros(); - throw_unsup!(AlignmentCheckFailed { + throw_ub!(AlignmentCheckFailed { has: Align::from_bytes(offset_pow2).unwrap(), required: align, }) @@ -359,7 +369,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { assert!(size.bytes() == 0); // Must be non-NULL. if bits == 0 { - throw_unsup!(InvalidNullPointerUsage) + throw_ub!(InvalidIntPointerUsage(0)) } // Must be aligned. if let Some(align) = align { @@ -374,7 +384,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // It is sufficient to check this for the end pointer. The addition // checks for overflow. let end_ptr = ptr.offset(size, self)?; - end_ptr.check_inbounds_alloc(allocation_size, msg)?; + if end_ptr.offset > allocation_size { + // equal is okay! + throw_ub!(PointerOutOfBounds { ptr: end_ptr.erase_tag(), msg, allocation_size }) + } // Test align. Check this last; if both bounds and alignment are violated // we want the error to be about the bounds. if let Some(align) = align { @@ -384,7 +397,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // got picked we might be aligned even if this check fails. // We instead have to fall back to converting to an integer and checking // the "real" alignment. - throw_unsup!(AlignmentCheckFailed { has: alloc_align, required: align }); + throw_ub!(AlignmentCheckFailed { has: alloc_align, required: align }); } check_offset_align(ptr.offset.bytes(), align)?; } @@ -401,7 +414,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { let (size, _align) = self .get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead) .expect("alloc info with MaybeDead cannot fail"); - ptr.check_inbounds_alloc(size, CheckInAllocMsg::NullPointerTest).is_err() + // If the pointer is out-of-bounds, it may be null. + // Note that one-past-the-end (offset == size) is still inbounds, and never null. + ptr.offset > size } } @@ -421,6 +436,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { /// The `GlobalAlloc::Memory` branch here is still reachable though; when a static /// contains a reference to memory that was created during its evaluation (i.e., not to /// another static), those inner references only exist in "resolved" form. + /// + /// Assumes `id` is already canonical. fn get_static_alloc( memory_extra: &M::MemoryExtra, tcx: TyCtxtAt<'tcx>, @@ -429,36 +446,35 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { let alloc = tcx.alloc_map.lock().get(id); let alloc = match alloc { Some(GlobalAlloc::Memory(mem)) => Cow::Borrowed(mem), - Some(GlobalAlloc::Function(..)) => throw_unsup!(DerefFunctionPointer), - None => throw_unsup!(DanglingPointerDeref), + Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), + None => throw_ub!(PointerUseAfterFree(id)), Some(GlobalAlloc::Static(def_id)) => { // We got a "lazy" static that has not been computed yet. if tcx.is_foreign_item(def_id) { - trace!("static_alloc: foreign item {:?}", def_id); - M::find_foreign_static(tcx.tcx, def_id)? - } else { - trace!("static_alloc: Need to compute {:?}", def_id); - let instance = Instance::mono(tcx.tcx, def_id); - let gid = GlobalId { instance, promoted: None }; - // use the raw query here to break validation cycles. Later uses of the static - // will call the full query anyway - let raw_const = - tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| { - // no need to report anything, the const_eval call takes care of that - // for statics - assert!(tcx.is_static(def_id)); - match err { - ErrorHandled::Reported => err_inval!(ReferencedConstant), - ErrorHandled::TooGeneric => err_inval!(TooGeneric), - } - })?; - // Make sure we use the ID of the resolved memory, not the lazy one! - let id = raw_const.alloc_id; - let allocation = tcx.alloc_map.lock().unwrap_memory(id); - - M::before_access_static(memory_extra, allocation)?; - Cow::Borrowed(allocation) + trace!("get_static_alloc: foreign item {:?}", def_id); + throw_unsup!(ReadForeignStatic(def_id)) } + trace!("get_static_alloc: Need to compute {:?}", def_id); + let instance = Instance::mono(tcx.tcx, def_id); + let gid = GlobalId { instance, promoted: None }; + // use the raw query here to break validation cycles. Later uses of the static + // will call the full query anyway + let raw_const = + tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| { + // no need to report anything, the const_eval call takes care of that + // for statics + assert!(tcx.is_static(def_id)); + match err { + ErrorHandled::Reported => err_inval!(ReferencedConstant), + ErrorHandled::TooGeneric => err_inval!(TooGeneric), + } + })?; + // Make sure we use the ID of the resolved memory, not the lazy one! + let id = raw_const.alloc_id; + let allocation = tcx.alloc_map.lock().unwrap_memory(id); + + M::before_access_static(memory_extra, allocation)?; + Cow::Borrowed(allocation) } }; // We got tcx memory. Let the machine initialize its "extra" stuff. @@ -478,6 +494,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { &self, id: AllocId, ) -> InterpResult<'tcx, &Allocation> { + let id = M::canonical_alloc_id(self, id); // The error type of the inner closure here is somewhat funny. We have two // ways of "erroring": An actual error, or because we got a reference from // `get_static_alloc` that we can actually use directly without inserting anything anywhere. @@ -513,6 +530,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { &mut self, id: AllocId, ) -> InterpResult<'tcx, &mut Allocation> { + let id = M::canonical_alloc_id(self, id); let tcx = self.tcx; let memory_extra = &self.extra; let a = self.alloc_map.get_mut_or(id, || { @@ -520,7 +538,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // to give us a cheap reference. let alloc = Self::get_static_alloc(memory_extra, tcx, id)?; if alloc.mutability == Mutability::Not { - throw_unsup!(ModifiedConstantMemory) + throw_ub!(WriteToReadOnly(id)) } match M::STATIC_KIND { Some(kind) => Ok((MemoryKind::Machine(kind), alloc.into_owned())), @@ -534,7 +552,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Ok(a) => { let a = &mut a.1; if a.mutability == Mutability::Not { - throw_unsup!(ModifiedConstantMemory) + throw_ub!(WriteToReadOnly(id)) } Ok(a) } @@ -550,6 +568,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { id: AllocId, liveness: AllocCheck, ) -> InterpResult<'static, (Size, Align)> { + let id = M::canonical_alloc_id(self, id); // # Regular allocations // Don't use `self.get_raw` here as that will // a) cause cycles in case `id` refers to a static @@ -560,10 +579,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // # Function pointers // (both global from `alloc_map` and local from `extra_fn_ptr_map`) - if let Ok(_) = self.get_fn_alloc(id) { + if self.get_fn_alloc(id).is_some() { return if let AllocCheck::Dereferenceable = liveness { // The caller requested no function pointers. - throw_unsup!(DerefFunctionPointer) + throw_ub!(DerefFunctionPointer(id)) } else { Ok((Size::ZERO, Align::from_bytes(1).unwrap())) }; @@ -591,25 +610,26 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { if let AllocCheck::MaybeDead = liveness { // Deallocated pointers are allowed, we should be able to find // them in the map. - Ok(*self.dead_alloc_map.get(&id).expect( - "deallocated pointers should all be recorded in \ - `dead_alloc_map`", - )) + Ok(*self + .dead_alloc_map + .get(&id) + .expect("deallocated pointers should all be recorded in `dead_alloc_map`")) } else { - throw_unsup!(DanglingPointerDeref) + throw_ub!(PointerUseAfterFree(id)) } } } } - fn get_fn_alloc(&self, id: AllocId) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { + /// Assumes `id` is already canonical. + fn get_fn_alloc(&self, id: AllocId) -> Option> { trace!("reading fn ptr: {}", id); if let Some(extra) = self.extra_fn_ptr_map.get(&id) { - Ok(FnVal::Other(*extra)) + Some(FnVal::Other(*extra)) } else { match self.tcx.alloc_map.lock().get(id) { - Some(GlobalAlloc::Function(instance)) => Ok(FnVal::Instance(instance)), - _ => throw_unsup!(ExecuteMemory), + Some(GlobalAlloc::Function(instance)) => Some(FnVal::Instance(instance)), + _ => None, } } } @@ -620,9 +640,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { let ptr = self.force_ptr(ptr)?; // We definitely need a pointer value. if ptr.offset.bytes() != 0 { - throw_unsup!(InvalidFunctionPointer) + throw_ub!(InvalidFunctionPointer(ptr.erase_tag())) } - self.get_fn_alloc(ptr.alloc_id) + let id = M::canonical_alloc_id(self, ptr.alloc_id); + self.get_fn_alloc(id).ok_or_else(|| err_ub!(InvalidFunctionPointer(ptr.erase_tag())).into()) } pub fn mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { @@ -791,6 +812,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { self.get_raw(ptr.alloc_id)?.read_c_str(self, ptr) } + /// Reads a 0x0000-terminated u16-sequence from memory. Returns them as a Vec. + /// Terminator 0x0000 is not included in the returned Vec. + /// + /// Performs appropriate bounds checks. + pub fn read_wide_str(&self, ptr: Scalar) -> InterpResult<'tcx, Vec> { + let size_2bytes = Size::from_bytes(2); + let align_2bytes = Align::from_bytes(2).unwrap(); + // We need to read at least 2 bytes, so we *need* a ptr. + let mut ptr = self.force_ptr(ptr)?; + let allocation = self.get_raw(ptr.alloc_id)?; + let mut u16_seq = Vec::new(); + + loop { + ptr = self + .check_ptr_access(ptr.into(), size_2bytes, align_2bytes)? + .expect("cannot be a ZST"); + let single_u16 = allocation.read_scalar(self, ptr, size_2bytes)?.to_u16()?; + if single_u16 != 0x0000 { + u16_seq.push(single_u16); + ptr = ptr.offset(size_2bytes, self)?; + } else { + break; + } + } + Ok(u16_seq) + } + /// Writes the given stream of bytes into memory. /// /// Performs appropriate bounds checks. diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index a519f38e712..c3fd9682765 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -24,7 +24,7 @@ pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind}; -pub use self::machine::{AllocMap, Machine, MayLeak, StackPopInfo}; +pub use self::machine::{AllocMap, Machine, MayLeak, StackPopJump}; pub use self::operand::{ImmTy, Immediate, OpTy, Operand, ScalarMaybeUndef}; diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index d1c08da6cbe..316cf2ee419 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -3,18 +3,20 @@ use std::convert::{TryFrom, TryInto}; -use rustc::ty::layout::{ - self, HasDataLayout, IntegerExt, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx, -}; -use rustc::{mir, ty}; - use super::{InterpCx, MPlaceTy, Machine, MemPlace, Place, PlaceTy}; pub use rustc::mir::interpret::ScalarMaybeUndef; use rustc::mir::interpret::{ sign_extend, truncate, AllocId, ConstValue, GlobalId, InterpResult, Pointer, Scalar, }; +use rustc::ty::layout::{ + self, HasDataLayout, IntegerExt, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx, +}; +use rustc::ty::print::{FmtPrinter, PrettyPrinter, Printer}; +use rustc::ty::Ty; +use rustc::{mir, ty}; +use rustc_hir::def::Namespace; use rustc_macros::HashStable; -use syntax::ast; +use std::fmt::Write; /// An `Immediate` represents a single immediate self-contained Rust value. /// @@ -92,47 +94,44 @@ pub struct ImmTy<'tcx, Tag = ()> { pub layout: TyLayout<'tcx>, } -// `Tag: Copy` because some methods on `Scalar` consume them by value impl std::fmt::Display for ImmTy<'tcx, Tag> { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.imm { - Immediate::Scalar(ScalarMaybeUndef::Scalar(s)) => match s.to_bits(self.layout.size) { - Ok(s) => { - match self.layout.ty.kind { - ty::Int(_) => { - return write!( - fmt, - "{}", - super::sign_extend(s, self.layout.size) as i128, - ); - } - ty::Uint(_) => return write!(fmt, "{}", s), - ty::Bool if s == 0 => return fmt.write_str("false"), - ty::Bool if s == 1 => return fmt.write_str("true"), - ty::Char => { - if let Some(c) = u32::try_from(s).ok().and_then(std::char::from_u32) { - return write!(fmt, "{}", c); - } - } - ty::Float(ast::FloatTy::F32) => { - if let Ok(u) = u32::try_from(s) { - return write!(fmt, "{}", f32::from_bits(u)); - } - } - ty::Float(ast::FloatTy::F64) => { - if let Ok(u) = u64::try_from(s) { - return write!(fmt, "{}", f64::from_bits(u)); - } - } - _ => {} - } - write!(fmt, "{:x}", s) + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + /// Helper function for printing a scalar to a FmtPrinter + fn p<'a, 'tcx, F: std::fmt::Write, Tag>( + cx: FmtPrinter<'a, 'tcx, F>, + s: ScalarMaybeUndef, + ty: Ty<'tcx>, + ) -> Result, std::fmt::Error> { + match s { + ScalarMaybeUndef::Scalar(s) => { + cx.pretty_print_const_scalar(s.erase_tag(), ty, true) } - Err(_) => fmt.write_str("{pointer}"), - }, - Immediate::Scalar(ScalarMaybeUndef::Undef) => fmt.write_str("{undef}"), - Immediate::ScalarPair(..) => fmt.write_str("{wide pointer or tuple}"), + ScalarMaybeUndef::Undef => cx.typed_value( + |mut this| { + this.write_str("{undef ")?; + Ok(this) + }, + |this| this.print_type(ty), + " ", + ), + } } + ty::tls::with(|tcx| { + match self.imm { + Immediate::Scalar(s) => { + if let Some(ty) = tcx.lift(&self.layout.ty) { + let cx = FmtPrinter::new(tcx, f, Namespace::ValueNS); + p(cx, s, ty)?; + return Ok(()); + } + write!(f, "{:?}: {}", s.erase_tag(), self.layout.ty) + } + Immediate::ScalarPair(a, b) => { + // FIXME(oli-obk): at least print tuples and slices nicely + write!(f, "({:?}, {:?}): {}", a.erase_tag(), b.erase_tag(), self.layout.ty,) + } + } + }) } } @@ -205,11 +204,6 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> { pub fn from_int(i: impl Into, layout: TyLayout<'tcx>) -> Self { Self::from_scalar(Scalar::from_int(i, layout.size), layout) } - - #[inline] - pub fn to_bits(self) -> InterpResult<'tcx, u128> { - self.to_scalar()?.to_bits(self.layout.size) - } } // Use the existing layout if given (but sanity check in debug mode), @@ -349,7 +343,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let len = mplace.len(self)?; let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?; let str = ::std::str::from_utf8(bytes) - .map_err(|err| err_unsup!(ValidationFailure(err.to_string())))?; + .map_err(|err| err_ub_format!("this string is not valid UTF-8: {}", err))?; Ok(str) } @@ -463,7 +457,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let base_op = match place.local { - mir::RETURN_PLACE => throw_unsup!(ReadFromReturnPointer), + mir::RETURN_PLACE => throw_ub!(ReadFromReturnPlace), local => { // Do not use the layout passed in as argument if the base we are looking at // here is not the entire place. @@ -509,7 +503,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, ops: &[mir::Operand<'tcx>], ) -> InterpResult<'tcx, Vec>> { - ops.into_iter().map(|op| self.eval_operand(op, None)).collect() + ops.iter().map(|op| self.eval_operand(op, None)).collect() } // Used when the miri-engine runs into a constant and for extracting information from constants @@ -518,7 +512,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// "universe" (param_env). crate fn eval_const_to_op( &self, - val: &'tcx ty::Const<'tcx>, + val: &ty::Const<'tcx>, layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let tag_scalar = |scalar| match scalar { @@ -536,7 +530,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // potentially requiring the current static to be evaluated again. This is not a // problem here, because we are building an operand which means an actual read is // happening. - return Ok(OpTy::from(self.const_eval(GlobalId { instance, promoted })?)); + return Ok(self.const_eval(GlobalId { instance, promoted }, val.ty)?); } ty::ConstKind::Infer(..) | ty::ConstKind::Bound(..) @@ -683,7 +677,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Then computing the absolute variant idx should not overflow any more. let variant_index = variants_start .checked_add(variant_index_relative) - .expect("oveflow computing absolute variant idx"); + .expect("overflow computing absolute variant idx"); let variants_len = rval .layout .ty diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index 2e8c94903ca..f2ee5e047a8 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -6,7 +6,7 @@ use rustc::ty::{ Ty, }; use rustc_apfloat::Float; -use syntax::ast::FloatTy; +use rustc_ast::ast::FloatTy; use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy}; @@ -234,7 +234,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty), Add | Sub | Mul | Rem | Div => { - debug_assert!(!left_layout.abi.is_signed()); + assert!(!left_layout.abi.is_signed()); let op: fn(u128, u128) -> (u128, bool) = match bin_op { Add => u128::overflowing_add, Sub => u128::overflowing_sub, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 4f96cb69891..107cfee5ace 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -410,6 +410,14 @@ where stride * field } layout::FieldPlacement::Union(count) => { + // This is a narrow bug-fix for rust-lang/rust#69191: if we are + // trying to access absent field of uninhabited variant, then + // signal UB (but don't ICE the compiler). + // FIXME temporary hack to work around incoherence between + // layout computation and MIR building + if field >= count as u64 && base.layout.abi == layout::Abi::Uninhabited { + throw_ub!(Unreachable); + } assert!( field < count as u64, "Tried to access field {} of union {:#?} with {} fields", @@ -647,7 +655,7 @@ where } local => PlaceTy { // This works even for dead/uninitialized locals; we check further when writing - place: Place::Local { frame: self.cur_frame(), local: local }, + place: Place::Local { frame: self.cur_frame(), local }, layout: self.layout_of_local(self.frame(), local, None)?, }, }; @@ -681,7 +689,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(self.place_to_op(dest)?, vec![], None)?; + self.validate_operand(self.place_to_op(dest)?)?; } Ok(()) @@ -698,7 +706,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(dest.into(), vec![], None)?; + self.validate_operand(dest.into())?; } Ok(()) @@ -835,7 +843,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(self.place_to_op(dest)?, vec![], None)?; + self.validate_operand(self.place_to_op(dest)?)?; } Ok(()) @@ -918,7 +926,7 @@ where // most likey we *are* running `typeck` right now. Investigate whether we can bail out // on `typeck_tables().has_errors` at all const eval entry points. debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); - throw_unsup!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); + throw_inval!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); } // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want // to avoid that here. @@ -943,7 +951,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(dest.into(), vec![], None)?; + self.validate_operand(dest.into())?; } Ok(()) diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index a8e67c8f208..ee45179fd8b 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -15,12 +15,12 @@ use rustc::mir::interpret::{ use rustc::ty::layout::{Align, Size}; use rustc::ty::{self, TyCtxt}; +use rustc_ast::ast::Mutability; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_span::source_map::Span; -use syntax::ast::Mutability; use super::eval_context::{LocalState, StackPopCleanup}; use super::{ @@ -292,7 +292,7 @@ where let all_bytes = 0..self.len(); // This 'inspect' is okay since following access respects undef and relocations. This does - // influence interpreter exeuction, but only to detect the error of cycles in evalution + // influence interpreter exeuction, but only to detect the error of cycles in evaluation // dependencies. let bytes = self.inspect_with_undef_and_ptr_outside_interpreter(all_bytes); diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 7d59c0181a8..f298a6677d6 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -287,7 +287,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.eval_terminator(terminator)?; if !self.stack.is_empty() { // This should change *something* - debug_assert!(self.cur_frame() != old_stack || self.frame().block != old_bb); + assert!(self.cur_frame() != old_stack || self.frame().block != old_bb); if let Some(block) = self.frame().block { info!("// executing {:?}", block); } diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 37dcab512b9..22a081a9c8e 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -95,10 +95,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if expected == cond_val { self.go_to_block(target); } else { - M::assert_panic(self, terminator.source_info.span, msg, cleanup)?; + M::assert_panic(self, msg, cleanup)?; } } + Abort => { + M::abort(self)?; + } + // When we encounter Resume, we've finished unwinding // cleanup for the current stack frame. We pop it in order // to continue unwinding the next frame @@ -114,15 +118,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Unreachable => throw_ub!(Unreachable), // These should never occur for MIR we actually run. - DropAndReplace { .. } | FalseEdges { .. } | FalseUnwind { .. } => { + DropAndReplace { .. } + | FalseEdges { .. } + | FalseUnwind { .. } + | Yield { .. } + | GeneratorDrop => { bug!("{:#?} should have been eliminated by MIR pass", terminator.kind) } - - // These are not (yet) supported. It is unclear if they even can occur in - // MIR that we actually run. - Yield { .. } | GeneratorDrop | Abort => { - throw_unsup_format!("Unsupported terminator kind: {:#?}", terminator.kind) - } } Ok(()) @@ -170,13 +172,19 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { trace!("Skipping callee ZST"); return Ok(()); } - let caller_arg = caller_arg.next().ok_or_else(|| err_unsup!(FunctionArgCountMismatch))?; + let caller_arg = caller_arg.next().ok_or_else(|| { + err_ub_format!("calling a function with fewer arguments than it requires") + })?; if rust_abi { - debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out"); + assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out"); } // Now, check if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) { - throw_unsup!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty)) + throw_ub_format!( + "calling a function with argument of type {:?} passing data of type {:?}", + callee_arg.layout.ty, + caller_arg.layout.ty + ) } // We allow some transmutes here self.copy_op_transmute(caller_arg, callee_arg) @@ -221,7 +229,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { abi => abi, }; if normalize_abi(caller_abi) != normalize_abi(callee_abi) { - throw_unsup!(FunctionAbiMismatch(caller_abi, callee_abi)) + throw_ub_format!( + "calling a function with ABI {:?} using caller ABI {:?}", + callee_abi, + caller_abi + ) } } @@ -251,111 +263,108 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { StackPopCleanup::Goto { ret: ret.map(|p| p.1), unwind }, )?; - // We want to pop this frame again in case there was an error, to put - // the blame in the right location. Until the 2018 edition is used in - // the compiler, we have to do this with an immediately invoked function. - let res = - (|| { - trace!( - "caller ABI: {:?}, args: {:#?}", - caller_abi, - args.iter() - .map(|arg| (arg.layout.ty, format!("{:?}", **arg))) - .collect::>() - ); - trace!( - "spread_arg: {:?}, locals: {:#?}", - body.spread_arg, - body.args_iter() - .map(|local| ( - local, - self.layout_of_local(self.frame(), local, None).unwrap().ty - )) - .collect::>() - ); - - // Figure out how to pass which arguments. - // The Rust ABI is special: ZST get skipped. - let rust_abi = match caller_abi { - Abi::Rust | Abi::RustCall => true, - _ => false, + // If an error is raised here, pop the frame again to get an accurate backtrace. + // To this end, we wrap it all in a `try` block. + let res: InterpResult<'tcx> = try { + trace!( + "caller ABI: {:?}, args: {:#?}", + caller_abi, + args.iter() + .map(|arg| (arg.layout.ty, format!("{:?}", **arg))) + .collect::>() + ); + trace!( + "spread_arg: {:?}, locals: {:#?}", + body.spread_arg, + body.args_iter() + .map(|local| ( + local, + self.layout_of_local(self.frame(), local, None).unwrap().ty + )) + .collect::>() + ); + + // Figure out how to pass which arguments. + // The Rust ABI is special: ZST get skipped. + let rust_abi = match caller_abi { + Abi::Rust | Abi::RustCall => true, + _ => false, + }; + // We have two iterators: Where the arguments come from, + // and where they go to. + + // For where they come from: If the ABI is RustCall, we untuple the + // last incoming argument. These two iterators do not have the same type, + // so to keep the code paths uniform we accept an allocation + // (for RustCall ABI only). + let caller_args: Cow<'_, [OpTy<'tcx, M::PointerTag>]> = + if caller_abi == Abi::RustCall && !args.is_empty() { + // Untuple + let (&untuple_arg, args) = args.split_last().unwrap(); + trace!("eval_fn_call: Will pass last argument by untupling"); + Cow::from( + args.iter() + .map(|&a| Ok(a)) + .chain( + (0..untuple_arg.layout.fields.count()) + .map(|i| self.operand_field(untuple_arg, i as u64)), + ) + .collect::>>>( + )?, + ) + } else { + // Plain arg passing + Cow::from(args) }; - // We have two iterators: Where the arguments come from, - // and where they go to. - - // For where they come from: If the ABI is RustCall, we untuple the - // last incoming argument. These two iterators do not have the same type, - // so to keep the code paths uniform we accept an allocation - // (for RustCall ABI only). - let caller_args: Cow<'_, [OpTy<'tcx, M::PointerTag>]> = - if caller_abi == Abi::RustCall && !args.is_empty() { - // Untuple - let (&untuple_arg, args) = args.split_last().unwrap(); - trace!("eval_fn_call: Will pass last argument by untupling"); - Cow::from(args.iter().map(|&a| Ok(a)) - .chain((0..untuple_arg.layout.fields.count()).into_iter() - .map(|i| self.operand_field(untuple_arg, i as u64)) - ) - .collect::>>>()?) - } else { - // Plain arg passing - Cow::from(args) - }; - // Skip ZSTs - let mut caller_iter = caller_args - .iter() - .filter(|op| !rust_abi || !op.layout.is_zst()) - .map(|op| *op); - - // Now we have to spread them out across the callee's locals, - // taking into account the `spread_arg`. If we could write - // this is a single iterator (that handles `spread_arg`), then - // `pass_argument` would be the loop body. It takes care to - // not advance `caller_iter` for ZSTs. - let mut locals_iter = body.args_iter(); - while let Some(local) = locals_iter.next() { - let dest = self.eval_place(&mir::Place::from(local))?; - if Some(local) == body.spread_arg { - // Must be a tuple - for i in 0..dest.layout.fields.count() { - let dest = self.place_field(dest, i as u64)?; - self.pass_argument(rust_abi, &mut caller_iter, dest)?; - } - } else { - // Normal argument + // Skip ZSTs + let mut caller_iter = + caller_args.iter().filter(|op| !rust_abi || !op.layout.is_zst()).copied(); + + // Now we have to spread them out across the callee's locals, + // taking into account the `spread_arg`. If we could write + // this is a single iterator (that handles `spread_arg`), then + // `pass_argument` would be the loop body. It takes care to + // not advance `caller_iter` for ZSTs. + for local in body.args_iter() { + let dest = self.eval_place(&mir::Place::from(local))?; + if Some(local) == body.spread_arg { + // Must be a tuple + for i in 0..dest.layout.fields.count() { + let dest = self.place_field(dest, i as u64)?; self.pass_argument(rust_abi, &mut caller_iter, dest)?; } + } else { + // Normal argument + self.pass_argument(rust_abi, &mut caller_iter, dest)?; } - // Now we should have no more caller args - if caller_iter.next().is_some() { - trace!("Caller has passed too many args"); - throw_unsup!(FunctionArgCountMismatch) + } + // Now we should have no more caller args + if caller_iter.next().is_some() { + throw_ub_format!("calling a function with more arguments than it expected") + } + // Don't forget to check the return type! + if let Some((caller_ret, _)) = ret { + let callee_ret = self.eval_place(&mir::Place::return_place())?; + if !Self::check_argument_compat( + rust_abi, + caller_ret.layout, + callee_ret.layout, + ) { + throw_ub_format!( + "calling a function with return type {:?} passing \ + return place of type {:?}", + callee_ret.layout.ty, + caller_ret.layout.ty + ) } - // Don't forget to check the return type! - if let Some((caller_ret, _)) = ret { - let callee_ret = self.eval_place(&mir::Place::return_place())?; - if !Self::check_argument_compat( - rust_abi, - caller_ret.layout, - callee_ret.layout, - ) { - throw_unsup!(FunctionRetMismatch( - caller_ret.layout.ty, - callee_ret.layout.ty - )) - } - } else { - let local = mir::RETURN_PLACE; - let callee_layout = self.layout_of_local(self.frame(), local, None)?; - if !callee_layout.abi.is_uninhabited() { - throw_unsup!(FunctionRetMismatch( - self.tcx.types.never, - callee_layout.ty - )) - } + } else { + let local = mir::RETURN_PLACE; + let callee_layout = self.layout_of_local(self.frame(), local, None)?; + if !callee_layout.abi.is_uninhabited() { + throw_ub_format!("calling a returning function without a return place") } - Ok(()) - })(); + } + }; match res { Err(err) => { self.stack.pop(); diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index aa2b3040a71..d93b78a5bd5 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -29,7 +29,7 @@ macro_rules! throw_validation_failure { write_path(&mut msg, where_); } write!(&mut msg, ", but expected {}", $details).unwrap(); - throw_unsup!(ValidationFailure(msg)) + throw_ub!(ValidationFailure(msg)) }}; ($what:expr, $where:expr) => {{ let mut msg = format!("encountered {}", $what); @@ -38,7 +38,7 @@ macro_rules! throw_validation_failure { msg.push_str(" at "); write_path(&mut msg, where_); } - throw_unsup!(ValidationFailure(msg)) + throw_ub!(ValidationFailure(msg)) }}; } @@ -46,6 +46,8 @@ macro_rules! try_validation { ($e:expr, $what:expr, $where:expr, $details:expr) => {{ match $e { Ok(x) => x, + // We re-throw the error, so we are okay with allocation: + // this can only slow down builds that fail anyway. Err(_) => throw_validation_failure!($what, $where, $details), } }}; @@ -53,6 +55,8 @@ macro_rules! try_validation { ($e:expr, $what:expr, $where:expr) => {{ match $e { Ok(x) => x, + // We re-throw the error, so we are okay with allocation: + // this can only slow down builds that fail anyway. Err(_) => throw_validation_failure!($what, $where), } }}; @@ -67,11 +71,12 @@ pub enum PathElem { Field(Symbol), Variant(Symbol), GeneratorState(VariantIdx), - ClosureVar(Symbol), + CapturedVar(Symbol), ArrayElem(usize), TupleElem(usize), Deref, - Tag, + EnumTag, + GeneratorTag, DynDowncast, } @@ -109,9 +114,11 @@ fn write_path(out: &mut String, path: &Vec) { for elem in path.iter() { match elem { Field(name) => write!(out, ".{}", name), - Variant(name) => write!(out, ".", name), + EnumTag => write!(out, "."), + Variant(name) => write!(out, ".", name), + GeneratorTag => write!(out, "."), GeneratorState(idx) => write!(out, ".", idx.index()), - ClosureVar(name) => write!(out, ".", name), + CapturedVar(name) => write!(out, ".", name), TupleElem(idx) => write!(out, ".{}", idx), ArrayElem(idx) => write!(out, "[{}]", idx), // `.` does not match Rust syntax, but it is more readable for long paths -- and @@ -119,7 +126,6 @@ fn write_path(out: &mut String, path: &Vec) { // even use the usual syntax because we are just showing the projections, // not the root. Deref => write!(out, "."), - Tag => write!(out, "."), DynDowncast => write!(out, "."), } .unwrap() @@ -142,16 +148,16 @@ fn wrapping_range_contains(r: &RangeInclusive, test: u128) -> bool { // "expected something " makes sense. fn wrapping_range_format(r: &RangeInclusive, max_hi: u128) -> String { let (lo, hi) = r.clone().into_inner(); - debug_assert!(hi <= max_hi); + assert!(hi <= max_hi); if lo > hi { format!("less or equal to {}, or greater or equal to {}", hi, lo) } else if lo == hi { format!("equal to {}", lo) } else if lo == 0 { - debug_assert!(hi < max_hi, "should not be printing if the range covers everything"); + assert!(hi < max_hi, "should not be printing if the range covers everything"); format!("less or equal to {}", hi) } else if hi == max_hi { - debug_assert!(lo > 0, "should not be printing if the range covers everything"); + assert!(lo > 0, "should not be printing if the range covers everything"); format!("greater or equal to {}", lo) } else { format!("in the range {:?}", r) @@ -165,11 +171,27 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { path: Vec, ref_tracking_for_consts: Option<&'rt mut RefTracking, Vec>>, + may_ref_to_static: bool, ecx: &'rt InterpCx<'mir, 'tcx, M>, } impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M> { fn aggregate_field_path_elem(&mut self, layout: TyLayout<'tcx>, field: usize) -> PathElem { + // First, check if we are projecting to a variant. + match layout.variants { + layout::Variants::Multiple { discr_index, .. } => { + if discr_index == field { + return match layout.ty.kind { + ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag, + ty::Generator(..) => PathElem::GeneratorTag, + _ => bug!("non-variant type {:?}", layout.ty), + }; + } + } + layout::Variants::Single { .. } => {} + } + + // Now we know we are projecting to a field, so figure out which one. match layout.ty.kind { // generators and closures. ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { @@ -190,7 +212,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M } } - PathElem::ClosureVar(name.unwrap_or_else(|| { + PathElem::CapturedVar(name.unwrap_or_else(|| { // Fall back to showing the field index. sym::integer(field) })) @@ -201,13 +223,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M // enums ty::Adt(def, ..) if def.is_enum() => { - // we might be projecting *to* a variant, or to a field *in*a variant. + // we might be projecting *to* a variant, or to a field *in* a variant. match layout.variants { layout::Variants::Single { index } => { // Inside a variant PathElem::Field(def.variants[index].fields[field].ident.name) } - _ => bug!(), + layout::Variants::Multiple { .. } => bug!("we handled variants above"), } } @@ -288,195 +310,192 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M Ok(()) } -} -impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> - for ValidityVisitor<'rt, 'mir, 'tcx, M> -{ - type V = OpTy<'tcx, M::PointerTag>; - - #[inline(always)] - fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { - &self.ecx - } - - #[inline] - fn visit_field( + /// Check a reference or `Box`. + fn check_safe_pointer( &mut self, - old_op: OpTy<'tcx, M::PointerTag>, - field: usize, - new_op: OpTy<'tcx, M::PointerTag>, + value: OpTy<'tcx, M::PointerTag>, + kind: &str, ) -> InterpResult<'tcx> { - let elem = self.aggregate_field_path_elem(old_op.layout, field); - self.visit_elem(new_op, elem) - } - - #[inline] - fn visit_variant( - &mut self, - old_op: OpTy<'tcx, M::PointerTag>, - variant_id: VariantIdx, - new_op: OpTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - let name = match old_op.layout.ty.kind { - ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name), - // Generators also have variants - ty::Generator(..) => PathElem::GeneratorState(variant_id), - _ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty), - }; - self.visit_elem(new_op, name) - } - - #[inline] - fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { - trace!("visit_value: {:?}, {:?}", *op, op.layout); - // Translate some possible errors to something nicer. - match self.walk_value(op) { - Ok(()) => Ok(()), + let value = self.ecx.read_immediate(value)?; + // Handle wide pointers. + // Check metadata early, for better diagnostics + let place = try_validation!(self.ecx.ref_to_mplace(value), "undefined pointer", self.path); + if place.layout.is_unsized() { + self.check_wide_ptr_meta(place.meta, place.layout)?; + } + // Make sure this is dereferenceable and all. + let size_and_align = match self.ecx.size_and_align_of(place.meta, place.layout) { + Ok(res) => res, Err(err) => match err.kind { - err_ub!(InvalidDiscriminant(val)) => { - throw_validation_failure!(val, self.path, "a valid enum discriminant") + err_ub!(InvalidMeta(msg)) => throw_validation_failure!( + format_args!("invalid {} metadata: {}", kind, msg), + self.path + ), + _ => bug!("Unexpected error during ptr size_and_align_of: {}", err), + }, + }; + let (size, align) = size_and_align + // for the purpose of validity, consider foreign types to have + // alignment and size determined by the layout (size will be 0, + // alignment should take attributes into account). + .unwrap_or_else(|| (place.layout.size, place.layout.align.abi)); + let ptr: Option<_> = match self.ecx.memory.check_ptr_access_align( + place.ptr, + size, + Some(align), + CheckInAllocMsg::InboundsTest, + ) { + Ok(ptr) => ptr, + Err(err) => { + info!( + "{:?} did not pass access check for size {:?}, align {:?}", + place.ptr, size, align + ); + match err.kind { + err_ub!(InvalidIntPointerUsage(0)) => { + throw_validation_failure!(format_args!("a NULL {}", kind), self.path) + } + err_ub!(InvalidIntPointerUsage(i)) => throw_validation_failure!( + format_args!("a {} to unallocated address {}", kind, i), + self.path + ), + err_ub!(AlignmentCheckFailed { required, has }) => throw_validation_failure!( + format_args!( + "an unaligned {} (required {} byte alignment but found {})", + kind, + required.bytes(), + has.bytes() + ), + self.path + ), + err_unsup!(ReadBytesAsPointer) => throw_validation_failure!( + format_args!("a dangling {} (created from integer)", kind), + self.path + ), + err_ub!(PointerOutOfBounds { .. }) => throw_validation_failure!( + format_args!( + "a dangling {} (going beyond the bounds of its allocation)", + kind + ), + self.path + ), + // This cannot happen during const-eval (because interning already detects + // dangling pointers), but it can happen in Miri. + err_ub!(PointerUseAfterFree(_)) => throw_validation_failure!( + format_args!("a dangling {} (use-after-free)", kind), + self.path + ), + _ => bug!("Unexpected error during ptr inbounds test: {}", err), } - err_unsup!(ReadPointerAsBytes) => { - throw_validation_failure!("a pointer", self.path, "plain (non-pointer) bytes") + } + }; + // Recursive checking + if let Some(ref mut ref_tracking) = self.ref_tracking_for_consts { + if let Some(ptr) = ptr { + // not a ZST + // Skip validation entirely for some external statics + let alloc_kind = self.ecx.tcx.alloc_map.lock().get(ptr.alloc_id); + if let Some(GlobalAlloc::Static(did)) = alloc_kind { + // `extern static` cannot be validated as they have no body. + // FIXME: Statics from other crates are also skipped. + // They might be checked at a different type, but for now we + // want to avoid recursing too deeply. This is not sound! + if !did.is_local() || self.ecx.tcx.is_foreign_item(did) { + return Ok(()); + } + if !self.may_ref_to_static && self.ecx.tcx.is_static(did) { + throw_validation_failure!( + format_args!("a {} pointing to a static variable", kind), + self.path + ); + } } - _ => Err(err), - }, + } + // Proceed recursively even for ZST, no reason to skip them! + // `!` is a ZST and we want to validate it. + // Normalize before handing `place` to tracking because that will + // check for duplicates. + let place = if size.bytes() > 0 { + self.ecx.force_mplace_ptr(place).expect("we already bounds-checked") + } else { + place + }; + let path = &self.path; + ref_tracking.track(place, || { + // We need to clone the path anyway, make sure it gets created + // with enough space for the additional `Deref`. + let mut new_path = Vec::with_capacity(path.len() + 1); + new_path.clone_from(path); + new_path.push(PathElem::Deref); + new_path + }); } + Ok(()) } - fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { - let value = self.ecx.read_immediate(value)?; + /// Check if this is a value of primitive type, and if yes check the validity of the value + /// at that type. Return `true` if the type is indeed primitive. + fn try_visit_primitive( + &mut self, + value: OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, bool> { // Go over all the primitive types let ty = value.layout.ty; match ty.kind { ty::Bool => { - let value = value.to_scalar_or_undef(); + let value = self.ecx.read_scalar(value)?; try_validation!(value.to_bool(), value, self.path, "a boolean"); + Ok(true) } ty::Char => { - let value = value.to_scalar_or_undef(); + let value = self.ecx.read_scalar(value)?; try_validation!(value.to_char(), value, self.path, "a valid unicode codepoint"); + Ok(true) } ty::Float(_) | ty::Int(_) | ty::Uint(_) => { + let value = self.ecx.read_scalar(value)?; // NOTE: Keep this in sync with the array optimization for int/float // types below! - let size = value.layout.size; - let value = value.to_scalar_or_undef(); if self.ref_tracking_for_consts.is_some() { // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous - try_validation!( - value.to_bits(size), - value, - self.path, - "initialized plain (non-pointer) bytes" - ); + let is_bits = value.not_undef().map_or(false, |v| v.is_bits()); + if !is_bits { + throw_validation_failure!( + value, + self.path, + "initialized plain (non-pointer) bytes" + ) + } } else { // At run-time, for now, we accept *anything* for these types, including // undef. We should fix that, but let's start low. } + Ok(true) } ty::RawPtr(..) => { // We are conservative with undef for integers, but try to // actually enforce our current rules for raw pointers. - let place = - try_validation!(self.ecx.ref_to_mplace(value), "undefined pointer", self.path); + let place = try_validation!( + self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?), + "undefined pointer", + self.path + ); if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta, place.layout)?; } + Ok(true) } - _ if ty.is_box() || ty.is_region_ptr() => { - // Handle wide pointers. - // Check metadata early, for better diagnostics - let place = - try_validation!(self.ecx.ref_to_mplace(value), "undefined pointer", self.path); - if place.layout.is_unsized() { - self.check_wide_ptr_meta(place.meta, place.layout)?; - } - // Make sure this is dereferenceable and all. - let (size, align) = self - .ecx - .size_and_align_of(place.meta, place.layout)? - // for the purpose of validity, consider foreign types to have - // alignment and size determined by the layout (size will be 0, - // alignment should take attributes into account). - .unwrap_or_else(|| (place.layout.size, place.layout.align.abi)); - let ptr: Option<_> = match self.ecx.memory.check_ptr_access_align( - place.ptr, - size, - Some(align), - CheckInAllocMsg::InboundsTest, - ) { - Ok(ptr) => ptr, - Err(err) => { - info!( - "{:?} did not pass access check for size {:?}, align {:?}", - place.ptr, size, align - ); - match err.kind { - err_unsup!(InvalidNullPointerUsage) => { - throw_validation_failure!("NULL reference", self.path) - } - err_unsup!(AlignmentCheckFailed { required, has }) => { - throw_validation_failure!( - format_args!( - "unaligned reference \ - (required {} byte alignment but found {})", - required.bytes(), - has.bytes() - ), - self.path - ) - } - err_unsup!(ReadBytesAsPointer) => throw_validation_failure!( - "dangling reference (created from integer)", - self.path - ), - _ => throw_validation_failure!( - "dangling reference (not entirely in bounds)", - self.path - ), - } - } - }; - // Recursive checking - if let Some(ref mut ref_tracking) = self.ref_tracking_for_consts { - if let Some(ptr) = ptr { - // not a ZST - // Skip validation entirely for some external statics - let alloc_kind = self.ecx.tcx.alloc_map.lock().get(ptr.alloc_id); - if let Some(GlobalAlloc::Static(did)) = alloc_kind { - // `extern static` cannot be validated as they have no body. - // FIXME: Statics from other crates are also skipped. - // They might be checked at a different type, but for now we - // want to avoid recursing too deeply. This is not sound! - if !did.is_local() || self.ecx.tcx.is_foreign_item(did) { - return Ok(()); - } - } - } - // Proceed recursively even for ZST, no reason to skip them! - // `!` is a ZST and we want to validate it. - // Normalize before handing `place` to tracking because that will - // check for duplicates. - let place = if size.bytes() > 0 { - self.ecx.force_mplace_ptr(place).expect("we already bounds-checked") - } else { - place - }; - let path = &self.path; - ref_tracking.track(place, || { - // We need to clone the path anyway, make sure it gets created - // with enough space for the additional `Deref`. - let mut new_path = Vec::with_capacity(path.len() + 1); - new_path.clone_from(path); - new_path.push(PathElem::Deref); - new_path - }); - } + ty::Ref(..) => { + self.check_safe_pointer(value, "reference")?; + Ok(true) + } + ty::Adt(def, ..) if def.is_box() => { + self.check_safe_pointer(value, "box")?; + Ok(true) } ty::FnPtr(_sig) => { - let value = value.to_scalar_or_undef(); + let value = self.ecx.read_scalar(value)?; let _fn = try_validation!( value.not_undef().and_then(|ptr| self.ecx.memory.get_fn(ptr)), value, @@ -484,27 +503,49 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> "a function pointer" ); // FIXME: Check if the signature matches + Ok(true) + } + ty::Never => throw_validation_failure!("a value of the never type `!`", self.path), + ty::Foreign(..) | ty::FnDef(..) => { + // Nothing to check. + Ok(true) } - // This should be all the primitive types - _ => bug!("Unexpected primitive type {}", value.layout.ty), + // The above should be all the (inhabited) primitive types. The rest is compound, we + // check them by visiting their fields/variants. + // (`Str` UTF-8 check happens in `visit_aggregate`, too.) + ty::Adt(..) + | ty::Tuple(..) + | ty::Array(..) + | ty::Slice(..) + | ty::Str + | ty::Dynamic(..) + | ty::Closure(..) + | ty::Generator(..) => Ok(false), + // Some types only occur during typechecking, they have no layout. + // We should not see them here and we could not check them anyway. + ty::Error + | ty::Infer(..) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Param(..) + | ty::Opaque(..) + | ty::UnnormalizedProjection(..) + | ty::Projection(..) + | ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty), } - Ok(()) - } - - fn visit_uninhabited(&mut self) -> InterpResult<'tcx> { - throw_validation_failure!("a value of an uninhabited type", self.path) } fn visit_scalar( &mut self, op: OpTy<'tcx, M::PointerTag>, - layout: &layout::Scalar, + scalar_layout: &layout::Scalar, ) -> InterpResult<'tcx> { let value = self.ecx.read_scalar(op)?; + let valid_range = &scalar_layout.valid_range; + let (lo, hi) = valid_range.clone().into_inner(); // Determine the allowed range - let (lo, hi) = layout.valid_range.clone().into_inner(); // `max_hi` is as big as the size fits - let max_hi = u128::max_value() >> (128 - op.layout.size.bits()); + let max_hi = u128::MAX >> (128 - op.layout.size.bits()); assert!(hi <= max_hi); // We could also write `(hi + 1) % (max_hi + 1) == lo` but `max_hi + 1` overflows for `u128` if (lo == 0 && hi == max_hi) || (hi + 1 == lo) { @@ -516,7 +557,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> value.not_undef(), value, self.path, - format_args!("something {}", wrapping_range_format(&layout.valid_range, max_hi),) + format_args!("something {}", wrapping_range_format(valid_range, max_hi),) ); let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) { Err(ptr) => { @@ -528,7 +569,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> self.path, format_args!( "something that cannot possibly fail to be {}", - wrapping_range_format(&layout.valid_range, max_hi) + wrapping_range_format(valid_range, max_hi) ) ) } @@ -541,7 +582,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> self.path, format_args!( "something that cannot possibly fail to be {}", - wrapping_range_format(&layout.valid_range, max_hi) + wrapping_range_format(valid_range, max_hi) ) ) } @@ -549,16 +590,122 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> Ok(data) => data, }; // Now compare. This is slightly subtle because this is a special "wrap-around" range. - if wrapping_range_contains(&layout.valid_range, bits) { + if wrapping_range_contains(&valid_range, bits) { Ok(()) } else { throw_validation_failure!( bits, self.path, - format_args!("something {}", wrapping_range_format(&layout.valid_range, max_hi)) + format_args!("something {}", wrapping_range_format(valid_range, max_hi)) ) } } +} + +impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> + for ValidityVisitor<'rt, 'mir, 'tcx, M> +{ + type V = OpTy<'tcx, M::PointerTag>; + + #[inline(always)] + fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { + &self.ecx + } + + #[inline] + fn visit_field( + &mut self, + old_op: OpTy<'tcx, M::PointerTag>, + field: usize, + new_op: OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + let elem = self.aggregate_field_path_elem(old_op.layout, field); + self.visit_elem(new_op, elem) + } + + #[inline] + fn visit_variant( + &mut self, + old_op: OpTy<'tcx, M::PointerTag>, + variant_id: VariantIdx, + new_op: OpTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx> { + let name = match old_op.layout.ty.kind { + ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name), + // Generators also have variants + ty::Generator(..) => PathElem::GeneratorState(variant_id), + _ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty), + }; + self.visit_elem(new_op, name) + } + + #[inline(always)] + fn visit_union(&mut self, op: OpTy<'tcx, M::PointerTag>, fields: usize) -> InterpResult<'tcx> { + // Empty unions are not accepted by rustc. But uninhabited enums + // claim to be unions, so allow them, too. + assert!(op.layout.abi.is_uninhabited() || fields > 0); + Ok(()) + } + + #[inline] + fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + trace!("visit_value: {:?}, {:?}", *op, op.layout); + + // Check primitive types -- the leafs of our recursive descend. + if self.try_visit_primitive(op)? { + return Ok(()); + } + // Sanity check: `builtin_deref` does not know any pointers that are not primitive. + assert!(op.layout.ty.builtin_deref(true).is_none()); + + // Recursively walk the type. Translate some possible errors to something nicer. + match self.walk_value(op) { + Ok(()) => {} + Err(err) => match err.kind { + err_ub!(InvalidDiscriminant(val)) => { + throw_validation_failure!(val, self.path, "a valid enum discriminant") + } + err_unsup!(ReadPointerAsBytes) => { + throw_validation_failure!("a pointer", self.path, "plain (non-pointer) bytes") + } + // Propagate upwards (that will also check for unexpected errors). + _ => return Err(err), + }, + } + + // *After* all of this, check the ABI. We need to check the ABI to handle + // types like `NonNull` where the `Scalar` info is more restrictive than what + // the fields say (`rustc_layout_scalar_valid_range_start`). + // But in most cases, this will just propagate what the fields say, + // and then we want the error to point at the field -- so, first recurse, + // then check ABI. + // + // FIXME: We could avoid some redundant checks here. For newtypes wrapping + // scalars, we do the same check on every "level" (e.g., first we check + // MyNewtype and then the scalar in there). + match op.layout.abi { + layout::Abi::Uninhabited => { + throw_validation_failure!( + format_args!("a value of uninhabited type {:?}", op.layout.ty), + self.path + ); + } + layout::Abi::Scalar(ref scalar_layout) => { + self.visit_scalar(op, scalar_layout)?; + } + layout::Abi::ScalarPair { .. } | layout::Abi::Vector { .. } => { + // These have fields that we already visited above, so we already checked + // all their scalar-level restrictions. + // There is also no equivalent to `rustc_layout_scalar_valid_range_start` + // that would make skipping them here an issue. + } + layout::Abi::Aggregate { .. } => { + // Nothing to do. + } + } + + Ok(()) + } fn visit_aggregate( &mut self, @@ -626,11 +773,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> Err(err) => { // For some errors we might be able to provide extra information match err.kind { - err_unsup!(ReadUndefBytes(offset)) => { + err_ub!(InvalidUndefBytes(Some(ptr))) => { // Some byte was undefined, determine which // element that byte belongs to so we can // provide an index. - let i = (offset.bytes() / layout.size.bytes()) as usize; + let i = (ptr.offset.bytes() / layout.size.bytes()) as usize; self.path.push(PathElem::ArrayElem(i)); throw_validation_failure!("undefined bytes", self.path) @@ -657,31 +804,59 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// This function checks the data at `op`. `op` is assumed to cover valid memory if it - /// is an indirect operand. - /// It will error if the bits at the destination do not match the ones described by the layout. - /// - /// `ref_tracking_for_consts` can be `None` to avoid recursive checking below references. - /// This also toggles between "run-time" (no recursion) and "compile-time" (with recursion) - /// validation (e.g., pointer values are fine in integers at runtime) and various other const - /// specific validation checks. - pub fn validate_operand( + fn validate_operand_internal( &self, op: OpTy<'tcx, M::PointerTag>, path: Vec, ref_tracking_for_consts: Option< &mut RefTracking, Vec>, >, + may_ref_to_static: bool, ) -> InterpResult<'tcx> { - trace!("validate_operand: {:?}, {:?}", *op, op.layout.ty); + trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty); // Construct a visitor - let mut visitor = ValidityVisitor { path, ref_tracking_for_consts, ecx: self }; + let mut visitor = + ValidityVisitor { path, ref_tracking_for_consts, may_ref_to_static, ecx: self }; // Try to cast to ptr *once* instead of all the time. let op = self.force_op_ptr(op).unwrap_or(op); - // Run it - visitor.visit_value(op) + // Run it. + match visitor.visit_value(op) { + Ok(()) => Ok(()), + Err(err) if matches!(err.kind, err_ub!(ValidationFailure { .. })) => Err(err), + Err(err) if cfg!(debug_assertions) => { + bug!("Unexpected error during validation: {}", err) + } + Err(err) => Err(err), + } + } + + /// This function checks the data at `op` to be const-valid. + /// `op` is assumed to cover valid memory if it is an indirect operand. + /// It will error if the bits at the destination do not match the ones described by the layout. + /// + /// `ref_tracking` is used to record references that we encounter so that they + /// can be checked recursively by an outside driving loop. + /// + /// `may_ref_to_static` controls whether references are allowed to point to statics. + #[inline(always)] + pub fn const_validate_operand( + &self, + op: OpTy<'tcx, M::PointerTag>, + path: Vec, + ref_tracking: &mut RefTracking, Vec>, + may_ref_to_static: bool, + ) -> InterpResult<'tcx> { + self.validate_operand_internal(op, path, Some(ref_tracking), may_ref_to_static) + } + + /// This function checks the data at `op` to be runtime-valid. + /// `op` is assumed to cover valid memory if it is an indirect operand. + /// It will error if the bits at the destination do not match the ones described by the layout. + #[inline(always)] + pub fn validate_operand(&self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + self.validate_operand_internal(op, vec![], None, false) } } diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index d2594e87071..8808fc70cf7 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -120,7 +120,7 @@ macro_rules! make_value_visitor { } /// Visits the given value as a union. No automatic recursion can happen here. #[inline(always)] - fn visit_union(&mut self, _v: Self::V) -> InterpResult<'tcx> + fn visit_union(&mut self, _v: Self::V, _fields: usize) -> InterpResult<'tcx> { Ok(()) } @@ -150,8 +150,9 @@ macro_rules! make_value_visitor { ) -> InterpResult<'tcx> { self.visit_value(new_val) } - /// Called when recursing into an enum variant. + /// This gives the visitor the chance to track the stack of nested fields that + /// we are descending through. #[inline(always)] fn visit_variant( &mut self, @@ -162,33 +163,6 @@ macro_rules! make_value_visitor { self.visit_value(new_val) } - /// Called whenever we reach a value with uninhabited layout. - /// Recursing to fields will *always* continue after this! This is not meant to control - /// whether and how we descend recursively/ into the scalar's fields if there are any, - /// it is meant to provide the chance for additional checks when a value of uninhabited - /// layout is detected. - #[inline(always)] - fn visit_uninhabited(&mut self) -> InterpResult<'tcx> - { Ok(()) } - /// Called whenever we reach a value with scalar layout. - /// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory if the - /// visitor is not even interested in scalars. - /// Recursing to fields will *always* continue after this! This is not meant to control - /// whether and how we descend recursively/ into the scalar's fields if there are any, - /// it is meant to provide the chance for additional checks when a value of scalar - /// layout is detected. - #[inline(always)] - fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> InterpResult<'tcx> - { Ok(()) } - - /// Called whenever we reach a value of primitive type. There can be no recursion - /// below such a value. This is the leaf function. - /// We do *not* provide an `ImmTy` here because some implementations might want - /// to write to the place this primitive lives in. - #[inline(always)] - fn visit_primitive(&mut self, _v: Self::V) -> InterpResult<'tcx> - { Ok(()) } - // Default recursors. Not meant to be overloaded. fn walk_aggregate( &mut self, @@ -204,23 +178,10 @@ macro_rules! make_value_visitor { fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx> { trace!("walk_value: type: {}", v.layout().ty); - // If this is a multi-variant layout, we have to find the right one and proceed with - // that. - match v.layout().variants { - layout::Variants::Multiple { .. } => { - let op = v.to_op(self.ecx())?; - let idx = self.ecx().read_discriminant(op)?.1; - let inner = v.project_downcast(self.ecx(), idx)?; - trace!("walk_value: variant layout: {:#?}", inner.layout()); - // recurse with the inner type - return self.visit_variant(v, idx, inner); - } - layout::Variants::Single { .. } => {} - } - // Even for single variants, we might be able to get a more refined type: - // If it is a trait object, switch to the actual type that was used to create it. + // Special treatment for special types, where the (static) layout is not sufficient. match v.layout().ty.kind { + // If it is a trait object, switch to the real type that was used to create it. ty::Dynamic(..) => { // immediate trait objects are not a thing let dest = v.to_op(self.ecx())?.assert_mem_place(self.ecx()); @@ -229,56 +190,16 @@ macro_rules! make_value_visitor { // recurse with the inner type return self.visit_field(v, 0, Value::from_mem_place(inner)); }, - ty::Generator(..) => { - // FIXME: Generator layout is lying: it claims a whole bunch of fields exist - // when really many of them can be uninitialized. - // Just treat them as a union for now, until hopefully the layout - // computation is fixed. - return self.visit_union(v); - } + // Slices do not need special handling here: they have `Array` field + // placement with length 0, so we enter the `Array` case below which + // indirectly uses the metadata to determine the actual length. _ => {}, }; - // If this is a scalar, visit it as such. - // Things can be aggregates and have scalar layout at the same time, and that - // is very relevant for `NonNull` and similar structs: We need to visit them - // at their scalar layout *before* descending into their fields. - // FIXME: We could avoid some redundant checks here. For newtypes wrapping - // scalars, we do the same check on every "level" (e.g., first we check - // MyNewtype and then the scalar in there). - match v.layout().abi { - layout::Abi::Uninhabited => { - self.visit_uninhabited()?; - } - layout::Abi::Scalar(ref layout) => { - self.visit_scalar(v, layout)?; - } - // FIXME: Should we do something for ScalarPair? Vector? - _ => {} - } - - // Check primitive types. We do this after checking the scalar layout, - // just to have that done as well. Primitives can have varying layout, - // so we check them separately and before aggregate handling. - // It is CRITICAL that we get this check right, or we might be - // validating the wrong thing! - let primitive = match v.layout().fields { - // Primitives appear as Union with 0 fields - except for Boxes and fat pointers. - layout::FieldPlacement::Union(0) => true, - _ => v.layout().ty.builtin_deref(true).is_some(), - }; - if primitive { - return self.visit_primitive(v); - } - - // Proceed into the fields. + // Visit the fields of this value. match v.layout().fields { layout::FieldPlacement::Union(fields) => { - // Empty unions are not accepted by rustc. That's great, it means we can - // use that as an unambiguous signal for detecting primitives. Make sure - // we did not miss any primitive. - assert!(fields > 0); - self.visit_union(v) + self.visit_union(v, fields)?; }, layout::FieldPlacement::Arbitrary { ref offsets, .. } => { // FIXME: We collect in a vec because otherwise there are lifetime @@ -288,18 +209,35 @@ macro_rules! make_value_visitor { v.project_field(self.ecx(), i as u64) }) .collect(); - self.visit_aggregate(v, fields.into_iter()) + self.visit_aggregate(v, fields.into_iter())?; }, layout::FieldPlacement::Array { .. } => { // Let's get an mplace first. let mplace = v.to_op(self.ecx())?.assert_mem_place(self.ecx()); // Now we can go over all the fields. + // This uses the *run-time length*, i.e., if we are a slice, + // the dynamic info from the metadata is used. let iter = self.ecx().mplace_array_fields(mplace)? .map(|f| f.and_then(|f| { Ok(Value::from_mem_place(f)) })); - self.visit_aggregate(v, iter) + self.visit_aggregate(v, iter)?; + } + } + + match v.layout().variants { + // If this is a multi-variant layout, find the right variant and proceed + // with *its* fields. + layout::Variants::Multiple { .. } => { + let op = v.to_op(self.ecx())?; + let idx = self.ecx().read_discriminant(op)?.1; + let inner = v.project_downcast(self.ecx(), idx)?; + trace!("walk_value: variant layout: {:#?}", inner.layout()); + // recurse with the inner type + self.visit_variant(v, idx, inner) } + // For single-variant layouts, we already did anything there is to do. + layout::Variants::Single { .. } => Ok(()) } } } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 4f1b90e34cf..7d3aba3ff03 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -1,6 +1,6 @@ /*! -Rust MIR: a lowered representation of Rust. Also: an experiment! +Rust MIR: a lowered representation of Rust. */ @@ -9,6 +9,9 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(const_if_match)] +#![feature(const_fn)] +#![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(drain_filter)] #![feature(exhaustive_patterns)] diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index dd2071a6c59..51760500b03 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -183,7 +183,6 @@ use rustc::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar}; use rustc::mir::mono::{InstantiationMode, MonoItem}; use rustc::mir::visit::Visitor as MirVisitor; use rustc::mir::{self, Local, Location}; -use rustc::session::config::EntryFnType; use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc::ty::print::obsolete::DefPathBasedNames; use rustc::ty::subst::{InternalSubsts, SubstsRef}; @@ -194,6 +193,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, DefIdMap, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_index::bit_set::GrowableBitSet; +use rustc_session::config::EntryFnType; use smallvec::SmallVec; use std::iter; @@ -357,7 +357,7 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = None; if let Ok(val) = tcx.const_eval_poly(def_id) { - collect_const(tcx, val, InternalSubsts::empty(), &mut neighbors); + collect_const_value(tcx, val, &mut neighbors); } } MonoItem::Fn(instance) => { @@ -401,10 +401,8 @@ fn record_accesses<'tcx>( // We collect this into a `SmallVec` to avoid calling `is_inlining_candidate` in the lock. // FIXME: Call `is_inlining_candidate` when pushing to `neighbors` in `collect_items_rec` // instead to avoid creating this `SmallVec`. - let accesses: SmallVec<[_; 128]> = callees - .into_iter() - .map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))) - .collect(); + let accesses: SmallVec<[_; 128]> = + callees.iter().map(|mono_item| (*mono_item, is_inlining_candidate(mono_item))).collect(); inlining_map.lock_mut().record_accesses(caller, &accesses); } @@ -826,11 +824,8 @@ fn find_vtable_types_for_unsizing<'tcx>( (&ty::Adt(source_adt_def, source_substs), &ty::Adt(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); - let kind = monomorphize::custom_coerce_unsize_info(tcx, source_ty, target_ty); - - let coerce_index = match kind { - CustomCoerceUnsized::Struct(i) => i, - }; + let CustomCoerceUnsized::Struct(coerce_index) = + monomorphize::custom_coerce_unsize_info(tcx, source_ty, target_ty); let source_fields = &source_adt_def.non_enum_variant().fields; let target_fields = &target_adt_def.non_enum_variant().fields; @@ -971,7 +966,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { let def_id = self.tcx.hir().local_def_id(item.hir_id); if let Ok(val) = self.tcx.const_eval_poly(def_id) { - collect_const(self.tcx, val, InternalSubsts::empty(), &mut self.output); + collect_const_value(self.tcx, val, &mut self.output); } } hir::ItemKind::Fn(..) => { @@ -988,7 +983,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) { match ii.kind { - hir::ImplItemKind::Method(hir::FnSig { .. }, _) => { + hir::ImplItemKind::Fn(hir::FnSig { .. }, _) => { let def_id = self.tcx.hir().local_def_id(ii.hir_id); self.push_if_root(def_id); } @@ -1093,9 +1088,9 @@ fn create_mono_items_for_default_impls<'tcx>( let param_env = ty::ParamEnv::reveal_all(); let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); let overridden_methods: FxHashSet<_> = - items.iter().map(|iiref| iiref.ident.modern()).collect(); + items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect(); for method in tcx.provided_trait_methods(trait_ref.def_id) { - if overridden_methods.contains(&method.ident.modern()) { + if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) { continue; } @@ -1185,18 +1180,10 @@ fn collect_const<'tcx>( tcx.subst_and_normalize_erasing_regions(param_substs, param_env, &constant); match substituted_constant.val { - ty::ConstKind::Value(ConstValue::Scalar(Scalar::Ptr(ptr))) => { - collect_miri(tcx, ptr.alloc_id, output) - } - ty::ConstKind::Value(ConstValue::Slice { data: alloc, start: _, end: _ }) - | ty::ConstKind::Value(ConstValue::ByRef { alloc, .. }) => { - for &((), id) in alloc.relocations().values() { - collect_miri(tcx, id, output); - } - } + ty::ConstKind::Value(val) => collect_const_value(tcx, val, output), ty::ConstKind::Unevaluated(def_id, substs, promoted) => { match tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) { - Ok(val) => collect_const(tcx, val, param_substs, output), + Ok(val) => collect_const_value(tcx, val, output), Err(ErrorHandled::Reported) => {} Err(ErrorHandled::TooGeneric) => { span_bug!(tcx.def_span(def_id), "collection encountered polymorphic constant",) @@ -1206,3 +1193,19 @@ fn collect_const<'tcx>( _ => {} } } + +fn collect_const_value<'tcx>( + tcx: TyCtxt<'tcx>, + value: ConstValue<'tcx>, + output: &mut Vec>, +) { + match value { + ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output), + ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => { + for &((), id) in alloc.relocations().values() { + collect_miri(tcx, id, output); + } + } + _ => {} + } +} diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index 8bc63bfcfcb..7177bf726d4 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -13,12 +13,12 @@ pub fn custom_coerce_unsize_info<'tcx>( let def_id = tcx.lang_items().coerce_unsized_trait().unwrap(); let trait_ref = ty::Binder::bind(ty::TraitRef { - def_id: def_id, + def_id, substs: tcx.mk_substs_trait(source_ty, &[target_ty.into()]), }); match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) { - traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { + Some(traits::VtableImpl(traits::VtableImplData { impl_def_id, .. })) => { tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap() } vtable => { diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index de45808a481..9b81d69ce69 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -680,13 +680,20 @@ fn characteristic_def_id_of_mono_item<'tcx>( if tcx.trait_of_item(def_id).is_some() { let self_ty = instance.substs.type_at(0); - // This is an implementation of a trait method. + // This is a default implementation of a trait method. return characteristic_def_id_of_type(self_ty).or(Some(def_id)); } if let Some(impl_def_id) = tcx.impl_of_method(def_id) { - // This is a method within an inherent impl, find out what the - // self-type is: + if tcx.sess.opts.incremental.is_some() + && tcx.trait_id_of_impl(impl_def_id) == tcx.lang_items().drop_trait() + { + // Put `Drop::drop` into the same cgu as `drop_in_place` + // since `drop_in_place` is the only thing that can + // call it. + return None; + } + // This is a method within an impl, find out what the self-type is: let impl_self_ty = tcx.subst_and_normalize_erasing_regions( instance.substs, ty::ParamEnv::reveal_all(), diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index bfd30ff5da5..c1d969a4b51 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -2,13 +2,13 @@ use rustc::mir::*; use rustc::ty::layout::VariantIdx; use rustc::ty::query::Providers; use rustc::ty::subst::{InternalSubsts, Subst}; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; -use rustc_span::{sym, Span}; +use rustc_span::Span; use rustc_target::spec::abi::Abi; use std::fmt; @@ -39,6 +39,11 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx None, ), ty::InstanceDef::FnPtrShim(def_id, ty) => { + // FIXME(eddyb) support generating shims for a "shallow type", + // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic + // `Foo` or `[String]` etc. + assert!(!ty.needs_subst()); + let trait_ = tcx.trait_of_item(def_id).unwrap(); let adjustment = match tcx.fn_trait_kind_from_lang_item(trait_) { Some(ty::ClosureKind::FnOnce) => Adjustment::Identity, @@ -68,7 +73,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx let fn_mut = tcx.lang_items().fn_mut_trait().unwrap(); let call_mut = tcx .associated_items(fn_mut) - .iter() + .in_definition_order() .find(|it| it.kind == ty::AssocKind::Method) .unwrap() .def_id; @@ -81,17 +86,21 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx None, ) } - ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty), + ty::InstanceDef::DropGlue(def_id, ty) => { + // FIXME(eddyb) support generating shims for a "shallow type", + // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic + // `Foo` or `[String]` etc. + assert!(!ty.needs_subst()); + + build_drop_shim(tcx, def_id, ty) + } ty::InstanceDef::CloneShim(def_id, ty) => { - let name = tcx.item_name(def_id); - if name == sym::clone { - build_clone_shim(tcx, def_id, ty) - } else if name == sym::clone_from { - debug!("make_shim({:?}: using default trait implementation", instance); - return tcx.optimized_mir(def_id); - } else { - bug!("builtin clone shim {:?} not supported", instance) - } + // FIXME(eddyb) support generating shims for a "shallow type", + // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic + // `Foo` or `[String]` etc. + assert!(!ty.needs_subst()); + + build_clone_shim(tcx, def_id, ty) } ty::InstanceDef::Virtual(..) => { bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance) diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index a5b467c1e10..aa9cad7ffc1 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -14,13 +14,13 @@ pub struct AddRetag; /// after the assignment, we can be sure to obtain the same place value. /// (Concurrent accesses by other threads are no problem as these are anyway non-atomic /// copies. Data races are UB.) -fn is_stable(place: PlaceRef<'_, '_>) -> bool { +fn is_stable(place: PlaceRef<'_>) -> bool { place.projection.iter().all(|elem| { match elem { // Which place this evaluates to can change with any memory write, // so cannot assume this to be stable. ProjectionElem::Deref => false, - // Array indices are intersting, but MIR building generates a *fresh* + // Array indices are interesting, but MIR building generates a *fresh* // temporary for every array access, so the index cannot be changed as // a side-effect. ProjectionElem::Index { .. } | @@ -34,7 +34,7 @@ fn is_stable(place: PlaceRef<'_, '_>) -> bool { } /// Determine whether this type may be a reference (or box), and thus needs retagging. -fn may_be_reference<'tcx>(ty: Ty<'tcx>) -> bool { +fn may_be_reference(ty: Ty<'tcx>) -> bool { match ty.kind { // Primitive types that are not references ty::Bool @@ -75,8 +75,8 @@ impl<'tcx> MirPass<'tcx> for AddRetag { { let source_info = SourceInfo { scope: OUTERMOST_SOURCE_SCOPE, - span: span, // FIXME: Consider using just the span covering the function - // argument declaration. + span, // FIXME: Consider using just the span covering the function + // argument declaration. }; // Gather all arguments, skip return value. let places = local_decls diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index 3263905eadb..af7af7388bd 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -1,10 +1,9 @@ //! Concrete error types for all operations which may be invalid in a certain const context. -use rustc::session::config::nightly_options; -use rustc::session::parse::feature_err; -use rustc::ty::TyCtxt; use rustc_errors::struct_span_err; use rustc_hir::def_id::DefId; +use rustc_session::config::nightly_options; +use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -15,9 +14,9 @@ pub trait NonConstOp: std::fmt::Debug { /// Whether this operation can be evaluated by miri. const IS_SUPPORTED_IN_MIRI: bool = true; - /// Returns a boolean indicating whether the feature gate that would allow this operation is - /// enabled, or `None` if such a feature gate does not exist. - fn feature_gate(_tcx: TyCtxt<'tcx>) -> Option { + /// Returns the `Symbol` corresponding to the feature gate that would enable this operation, + /// or `None` if such a feature gate does not exist. + fn feature_gate() -> Option { None } @@ -25,8 +24,11 @@ pub trait NonConstOp: std::fmt::Debug { /// /// This check should assume that we are not in a non-const `fn`, where all operations are /// legal. + /// + /// By default, it returns `true` if and only if this operation has a corresponding feature + /// gate and that gate is enabled. fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool { - Self::feature_gate(item.tcx).unwrap_or(false) + Self::feature_gate().map_or(false, |gate| item.tcx.features().enabled(gate)) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -55,8 +57,8 @@ pub trait NonConstOp: std::fmt::Debug { #[derive(Debug)] pub struct Downcast; impl NonConstOp for Downcast { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_if_match) + fn feature_gate() -> Option { + Some(sym::const_if_match) } } @@ -65,10 +67,8 @@ impl NonConstOp for Downcast { pub struct FnCallIndirect; impl NonConstOp for FnCallIndirect { fn emit_error(&self, item: &Item<'_, '_>, span: Span) { - let mut err = item - .tcx - .sess - .struct_span_err(span, &format!("function pointers are not allowed in const fn")); + let mut err = + item.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn"); err.emit(); } } @@ -149,8 +149,8 @@ impl NonConstOp for HeapAllocation { #[derive(Debug)] pub struct IfOrMatch; impl NonConstOp for IfOrMatch { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_if_match) + fn feature_gate() -> Option { + Some(sym::const_if_match) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -177,8 +177,8 @@ impl NonConstOp for LiveDrop { #[derive(Debug)] pub struct Loop; impl NonConstOp for Loop { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_loop) + fn feature_gate() -> Option { + Some(sym::const_loop) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -205,8 +205,8 @@ impl NonConstOp for CellBorrow { #[derive(Debug)] pub struct MutBorrow; impl NonConstOp for MutBorrow { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_mut_refs) + fn feature_gate() -> Option { + Some(sym::const_mut_refs) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -240,8 +240,8 @@ impl NonConstOp for MutBorrow { #[derive(Debug)] pub struct MutAddressOf; impl NonConstOp for MutAddressOf { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_mut_refs) + fn feature_gate() -> Option { + Some(sym::const_mut_refs) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -258,16 +258,16 @@ impl NonConstOp for MutAddressOf { #[derive(Debug)] pub struct MutDeref; impl NonConstOp for MutDeref { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_mut_refs) + fn feature_gate() -> Option { + Some(sym::const_mut_refs) } } #[derive(Debug)] pub struct Panic; impl NonConstOp for Panic { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_panic) + fn feature_gate() -> Option { + Some(sym::const_panic) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -284,8 +284,8 @@ impl NonConstOp for Panic { #[derive(Debug)] pub struct RawPtrComparison; impl NonConstOp for RawPtrComparison { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_compare_raw_pointers) + fn feature_gate() -> Option { + Some(sym::const_compare_raw_pointers) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -302,8 +302,8 @@ impl NonConstOp for RawPtrComparison { #[derive(Debug)] pub struct RawPtrDeref; impl NonConstOp for RawPtrDeref { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_raw_ptr_deref) + fn feature_gate() -> Option { + Some(sym::const_raw_ptr_deref) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -320,8 +320,8 @@ impl NonConstOp for RawPtrDeref { #[derive(Debug)] pub struct RawPtrToIntCast; impl NonConstOp for RawPtrToIntCast { - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_raw_ptr_to_usize_cast) + fn feature_gate() -> Option { + Some(sym::const_raw_ptr_to_usize_cast) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { @@ -388,11 +388,12 @@ pub struct UnionAccess; impl NonConstOp for UnionAccess { fn is_allowed_in_item(&self, item: &Item<'_, '_>) -> bool { // Union accesses are stable in all contexts except `const fn`. - item.const_kind() != ConstKind::ConstFn || Self::feature_gate(item.tcx).unwrap() + item.const_kind() != ConstKind::ConstFn + || item.tcx.features().enabled(Self::feature_gate().unwrap()) } - fn feature_gate(tcx: TyCtxt<'_>) -> Option { - Some(tcx.features().const_fn_union) + fn feature_gate() -> Option { + Some(sym::const_fn_union) } fn emit_error(&self, item: &Item<'_, '_>, span: Span) { diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index e509e8267cc..9359ec16533 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -1,7 +1,9 @@ -//! A copy of the `Qualif` trait in `qualify_consts.rs` that is suitable for the new validator. +//! Structural const qualification. +//! +//! See the `Qualif` trait for more info. use rustc::mir::*; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, AdtDef, Ty}; use rustc_span::DUMMY_SP; use super::Item as ConstCx; @@ -14,11 +16,16 @@ pub fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> ConstQualifs } /// A "qualif"(-ication) is a way to look for something "bad" in the MIR that would disqualify some -/// code for promotion or prevent it from evaluating at compile time. So `return true` means -/// "I found something bad, no reason to go on searching". `false` is only returned if we -/// definitely cannot find anything bad anywhere. +/// code for promotion or prevent it from evaluating at compile time. /// -/// The default implementations proceed structurally. +/// Normally, we would determine what qualifications apply to each type and error when an illegal +/// operation is performed on such a type. However, this was found to be too imprecise, especially +/// in the presence of `enum`s. If only a single variant of an enum has a certain qualification, we +/// needn't reject code unless it actually constructs and operates on the qualifed variant. +/// +/// To accomplish this, const-checking and promotion use a value-based analysis (as opposed to a +/// type-based one). Qualifications propagate structurally across variables: If a local (or a +/// projection of a local) is assigned a qualifed value, that local itself becomes qualifed. pub trait Qualif { /// The name of the file used to debug the dataflow analysis that computes this qualif. const ANALYSIS_NAME: &'static str; @@ -26,166 +33,27 @@ pub trait Qualif { /// Whether this `Qualif` is cleared when a local is moved from. const IS_CLEARED_ON_MOVE: bool = false; + /// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`. fn in_qualifs(qualifs: &ConstQualifs) -> bool; - /// Return the qualification that is (conservatively) correct for any value - /// of the type. - fn in_any_value_of_ty(_cx: &ConstCx<'_, 'tcx>, _ty: Ty<'tcx>) -> bool; - - fn in_projection_structurally( - cx: &ConstCx<'_, 'tcx>, - per_local: &mut impl FnMut(Local) -> bool, - place: PlaceRef<'_, 'tcx>, - ) -> bool { - if let [proj_base @ .., elem] = place.projection { - let base_qualif = Self::in_place( - cx, - per_local, - PlaceRef { local: place.local, projection: proj_base }, - ); - let qualif = base_qualif - && Self::in_any_value_of_ty( - cx, - Place::ty_from(place.local, proj_base, *cx.body, cx.tcx) - .projection_ty(cx.tcx, elem) - .ty, - ); - match elem { - ProjectionElem::Deref - | ProjectionElem::Subslice { .. } - | ProjectionElem::Field(..) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Downcast(..) => qualif, - - ProjectionElem::Index(local) => qualif || per_local(*local), - } - } else { - bug!("This should be called if projection is not empty"); - } - } - - fn in_projection( - cx: &ConstCx<'_, 'tcx>, - per_local: &mut impl FnMut(Local) -> bool, - place: PlaceRef<'_, 'tcx>, - ) -> bool { - Self::in_projection_structurally(cx, per_local, place) - } - - fn in_place( - cx: &ConstCx<'_, 'tcx>, - per_local: &mut impl FnMut(Local) -> bool, - place: PlaceRef<'_, 'tcx>, - ) -> bool { - match place { - PlaceRef { local, projection: [] } => per_local(local), - PlaceRef { local: _, projection: [.., _] } => Self::in_projection(cx, per_local, place), - } - } - - fn in_operand( - cx: &ConstCx<'_, 'tcx>, - per_local: &mut impl FnMut(Local) -> bool, - operand: &Operand<'tcx>, - ) -> bool { - match *operand { - Operand::Copy(ref place) | Operand::Move(ref place) => { - Self::in_place(cx, per_local, place.as_ref()) - } - - Operand::Constant(ref constant) => { - if constant.check_static_ptr(cx.tcx).is_some() { - // `mir_const_qualif` does return the qualifs in the final value of a `static`, - // so we could use value-based qualification here, but we shouldn't do this - // without a good reason. - // - // Note: this uses `constant.literal.ty` which is a reference or pointer to the - // type of the actual `static` item. - Self::in_any_value_of_ty(cx, constant.literal.ty) - } else if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val - { - assert!(promoted.is_none()); - // Don't peek inside trait associated constants. - if cx.tcx.trait_of_item(def_id).is_some() { - Self::in_any_value_of_ty(cx, constant.literal.ty) - } else { - let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def_id); - let qualif = Self::in_qualifs(&qualifs); - - // Just in case the type is more specific than - // the definition, e.g., impl associated const - // with type parameters, take it into account. - qualif && Self::in_any_value_of_ty(cx, constant.literal.ty) - } - } else { - false - } - } - } - } - - fn in_rvalue_structurally( - cx: &ConstCx<'_, 'tcx>, - per_local: &mut impl FnMut(Local) -> bool, - rvalue: &Rvalue<'tcx>, - ) -> bool { - match *rvalue { - Rvalue::NullaryOp(..) => false, - - Rvalue::Discriminant(ref place) | Rvalue::Len(ref place) => { - Self::in_place(cx, per_local, place.as_ref()) - } - - Rvalue::Use(ref operand) - | Rvalue::Repeat(ref operand, _) - | Rvalue::UnaryOp(_, ref operand) - | Rvalue::Cast(_, ref operand, _) => Self::in_operand(cx, per_local, operand), - - Rvalue::BinaryOp(_, ref lhs, ref rhs) - | Rvalue::CheckedBinaryOp(_, ref lhs, ref rhs) => { - Self::in_operand(cx, per_local, lhs) || Self::in_operand(cx, per_local, rhs) - } - - Rvalue::Ref(_, _, ref place) | Rvalue::AddressOf(_, ref place) => { - // Special-case reborrows to be more like a copy of the reference. - if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() { - let base_ty = Place::ty_from(place.local, proj_base, *cx.body, cx.tcx).ty; - if let ty::Ref(..) = base_ty.kind { - return Self::in_place( - cx, - per_local, - PlaceRef { local: place.local, projection: proj_base }, - ); - } - } - - Self::in_place(cx, per_local, place.as_ref()) - } - - Rvalue::Aggregate(_, ref operands) => { - operands.iter().any(|o| Self::in_operand(cx, per_local, o)) - } - } - } - - fn in_rvalue( - cx: &ConstCx<'_, 'tcx>, - per_local: &mut impl FnMut(Local) -> bool, - rvalue: &Rvalue<'tcx>, - ) -> bool { - Self::in_rvalue_structurally(cx, per_local, rvalue) - } - - fn in_call( - cx: &ConstCx<'_, 'tcx>, - _per_local: &mut impl FnMut(Local) -> bool, - _callee: &Operand<'tcx>, - _args: &[Operand<'tcx>], - return_ty: Ty<'tcx>, - ) -> bool { - // Be conservative about the returned value of a const fn. - Self::in_any_value_of_ty(cx, return_ty) - } + /// Returns `true` if *any* value of the given type could possibly have this `Qualif`. + /// + /// This function determines `Qualif`s when we cannot do a value-based analysis. Since qualif + /// propagation is context-insenstive, this includes function arguments and values returned + /// from a call to another function. + /// + /// It also determines the `Qualif`s for primitive types. + fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool; + + /// Returns `true` if this `Qualif` is inherent to the given struct or enum. + /// + /// By default, `Qualif`s propagate into ADTs in a structural way: An ADT only becomes + /// qualified if part of it is assigned a value with that `Qualif`. However, some ADTs *always* + /// have a certain `Qualif`, regardless of whether their fields have it. For example, a type + /// with a custom `Drop` impl is inherently `NeedsDrop`. + /// + /// Returning `true` for `in_adt_inherently` but `false` for `in_any_value_of_ty` is unsound. + fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &AdtDef) -> bool; } /// Constant containing interior mutability (`UnsafeCell`). @@ -206,26 +74,10 @@ impl Qualif for HasMutInterior { !ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP) } - fn in_rvalue( - cx: &ConstCx<'_, 'tcx>, - per_local: &mut impl FnMut(Local) -> bool, - rvalue: &Rvalue<'tcx>, - ) -> bool { - match *rvalue { - Rvalue::Aggregate(ref kind, _) => { - if let AggregateKind::Adt(def, ..) = **kind { - if Some(def.did) == cx.tcx.lang_items().unsafe_cell_type() { - let ty = rvalue.ty(*cx.body, cx.tcx); - assert_eq!(Self::in_any_value_of_ty(cx, ty), true); - return true; - } - } - } - - _ => {} - } - - Self::in_rvalue_structurally(cx, per_local, rvalue) + fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &AdtDef) -> bool { + // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently. + // It arises structurally for all other types. + Some(adt.did) == cx.tcx.lang_items().unsafe_cell_type() } } @@ -247,19 +99,127 @@ impl Qualif for NeedsDrop { ty.needs_drop(cx.tcx, cx.param_env) } - fn in_rvalue( - cx: &ConstCx<'_, 'tcx>, - per_local: &mut impl FnMut(Local) -> bool, - rvalue: &Rvalue<'tcx>, - ) -> bool { - if let Rvalue::Aggregate(ref kind, _) = *rvalue { + fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &AdtDef) -> bool { + adt.has_dtor(cx.tcx) + } +} + +// FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return. + +/// Returns `true` if this `Rvalue` contains qualif `Q`. +pub fn in_rvalue(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, rvalue: &Rvalue<'tcx>) -> bool +where + Q: Qualif, + F: FnMut(Local) -> bool, +{ + match rvalue { + Rvalue::NullaryOp(..) => Q::in_any_value_of_ty(cx, rvalue.ty(*cx.body, cx.tcx)), + + Rvalue::Discriminant(place) | Rvalue::Len(place) => { + in_place::(cx, in_local, place.as_ref()) + } + + Rvalue::Use(operand) + | Rvalue::Repeat(operand, _) + | Rvalue::UnaryOp(_, operand) + | Rvalue::Cast(_, operand, _) => in_operand::(cx, in_local, operand), + + Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { + in_operand::(cx, in_local, lhs) || in_operand::(cx, in_local, rhs) + } + + Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { + // Special-case reborrows to be more like a copy of the reference. + if let &[ref proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() { + let base_ty = Place::ty_from(place.local, proj_base, *cx.body, cx.tcx).ty; + if let ty::Ref(..) = base_ty.kind { + return in_place::( + cx, + in_local, + PlaceRef { local: place.local, projection: proj_base }, + ); + } + } + + in_place::(cx, in_local, place.as_ref()) + } + + Rvalue::Aggregate(kind, operands) => { + // Return early if we know that the struct or enum being constructed is always + // qualified. if let AggregateKind::Adt(def, ..) = **kind { - if def.has_dtor(cx.tcx) { + if Q::in_adt_inherently(cx, def) { return true; } } + + // Otherwise, proceed structurally... + operands.iter().any(|o| in_operand::(cx, in_local, o)) } + } +} - Self::in_rvalue_structurally(cx, per_local, rvalue) +/// Returns `true` if this `Place` contains qualif `Q`. +pub fn in_place(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, place: PlaceRef<'tcx>) -> bool +where + Q: Qualif, + F: FnMut(Local) -> bool, +{ + let mut projection = place.projection; + while let [ref proj_base @ .., proj_elem] = projection { + match *proj_elem { + ProjectionElem::Index(index) if in_local(index) => return true, + + ProjectionElem::Deref + | ProjectionElem::Field(_, _) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Downcast(_, _) + | ProjectionElem::Index(_) => {} + } + + let base_ty = Place::ty_from(place.local, proj_base, *cx.body, cx.tcx); + let proj_ty = base_ty.projection_ty(cx.tcx, proj_elem).ty; + if !Q::in_any_value_of_ty(cx, proj_ty) { + return false; + } + + projection = proj_base; + } + + assert!(projection.is_empty()); + in_local(place.local) +} + +/// Returns `true` if this `Operand` contains qualif `Q`. +pub fn in_operand(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, operand: &Operand<'tcx>) -> bool +where + Q: Qualif, + F: FnMut(Local) -> bool, +{ + let constant = match operand { + Operand::Copy(place) | Operand::Move(place) => { + return in_place::(cx, in_local, place.as_ref()); + } + + Operand::Constant(c) => c, + }; + + // Check the qualifs of the value of `const` items. + if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val { + assert!(promoted.is_none()); + // Don't peek inside trait associated constants. + if cx.tcx.trait_of_item(def_id).is_none() { + let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def_id); + if !Q::in_qualifs(&qualifs) { + return false; + } + + // Just in case the type is more specific than + // the definition, e.g., impl associated const + // with type parameters, take it into account. + } } + // Otherwise use the qualifs of the type. + Q::in_any_value_of_ty(cx, constant.literal.ty) } diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs index b804dc4b5b6..e42f64b5c73 100644 --- a/src/librustc_mir/transform/check_consts/resolver.rs +++ b/src/librustc_mir/transform/check_consts/resolver.rs @@ -8,14 +8,14 @@ use rustc_index::bit_set::BitSet; use std::marker::PhantomData; -use super::{Item, Qualif}; +use super::{qualifs, Item, Qualif}; use crate::dataflow::{self as old_dataflow, generic as dataflow}; /// A `Visitor` that propagates qualifs between locals. This defines the transfer function of /// `FlowSensitiveAnalysis`. /// /// This transfer does nothing when encountering an indirect assignment. Consumers should rely on -/// the `IndirectlyMutableLocals` dataflow pass to see if a `Local` may have become qualified via +/// the `MaybeMutBorrowedLocals` dataflow pass to see if a `Local` may have become qualified via /// an indirect assignment or function call. struct TransferFunction<'a, 'mir, 'tcx, Q> { item: &'a Item<'mir, 'tcx>, @@ -66,18 +66,15 @@ where fn apply_call_return_effect( &mut self, _block: BasicBlock, - func: &mir::Operand<'tcx>, - args: &[mir::Operand<'tcx>], + _func: &mir::Operand<'tcx>, + _args: &[mir::Operand<'tcx>], return_place: &mir::Place<'tcx>, ) { + // We cannot reason about another function's internals, so use conservative type-based + // qualification for the result of a function call. let return_ty = return_place.ty(*self.item.body, self.item.tcx).ty; - let qualif = Q::in_call( - self.item, - &mut |l| self.qualifs_per_local.contains(l), - func, - args, - return_ty, - ); + let qualif = Q::in_any_value_of_ty(self.item, return_ty); + if !return_place.is_indirect() { self.assign_qualif_direct(return_place, qualif); } @@ -110,7 +107,11 @@ where rvalue: &mir::Rvalue<'tcx>, location: Location, ) { - let qualif = Q::in_rvalue(self.item, &mut |l| self.qualifs_per_local.contains(l), rvalue); + let qualif = qualifs::in_rvalue::( + self.item, + &mut |l| self.qualifs_per_local.contains(l), + rvalue, + ); if !place.is_indirect() { self.assign_qualif_direct(place, qualif); } @@ -125,8 +126,12 @@ where // here; that occurs in `apply_call_return_effect`. if let mir::TerminatorKind::DropAndReplace { value, location: dest, .. } = kind { - let qualif = - Q::in_operand(self.item, &mut |l| self.qualifs_per_local.contains(l), value); + let qualif = qualifs::in_operand::( + self.item, + &mut |l| self.qualifs_per_local.contains(l), + value, + ); + if !dest.is_indirect() { self.assign_qualif_direct(dest, qualif); } diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index e9715f682b0..be461c0e03d 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -3,29 +3,33 @@ use rustc::middle::lang_items; use rustc::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc::mir::*; -use rustc::traits::{self, TraitEngine}; use rustc::ty::cast::CastTy; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, Instance, InstanceDef, TyCtxt}; use rustc_errors::struct_span_err; use rustc_hir::{def_id::DefId, HirId}; use rustc_index::bit_set::BitSet; +use rustc_infer::infer::TyCtxtInferExt; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::{self, TraitEngine}; use std::borrow::Cow; use std::ops::Deref; -use self::old_dataflow::IndirectlyMutableLocals; use super::ops::{self, NonConstOp}; use super::qualifs::{self, HasMutInterior, NeedsDrop}; use super::resolver::FlowSensitiveAnalysis; use super::{is_lang_panic_fn, ConstKind, Item, Qualif}; use crate::const_eval::{is_const_fn, is_unstable_const_fn}; -use crate::dataflow::{self as old_dataflow, generic as dataflow}; -use dataflow::Analysis; +use crate::dataflow::generic::{self as dataflow, Analysis}; +use crate::dataflow::MaybeMutBorrowedLocals; +// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated +// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals` +// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`. pub type IndirectlyMutableResults<'mir, 'tcx> = - old_dataflow::DataflowResultsCursor<'mir, 'tcx, IndirectlyMutableLocals<'mir, 'tcx>>; + dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>; struct QualifCursor<'a, 'mir, 'tcx, Q: Qualif> { cursor: dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>>, @@ -58,7 +62,7 @@ pub struct Qualifs<'a, 'mir, 'tcx> { impl Qualifs<'a, 'mir, 'tcx> { fn indirectly_mutable(&mut self, local: Local, location: Location) -> bool { - self.indirectly_mutable.seek(location); + self.indirectly_mutable.seek_before(location); self.indirectly_mutable.get().contains(local) } @@ -134,22 +138,21 @@ impl Deref for Validator<'_, 'mir, 'tcx> { impl Validator<'a, 'mir, 'tcx> { pub fn new(item: &'a Item<'mir, 'tcx>) -> Self { + let Item { tcx, body, def_id, param_env, .. } = *item; + let needs_drop = QualifCursor::new(NeedsDrop, item); let has_mut_interior = QualifCursor::new(HasMutInterior, item); - let dead_unwinds = BitSet::new_empty(item.body.basic_blocks().len()); - let indirectly_mutable = old_dataflow::do_dataflow( - item.tcx, - &*item.body, - item.def_id, - &item.tcx.get_attrs(item.def_id), - &dead_unwinds, - old_dataflow::IndirectlyMutableLocals::new(item.tcx, *item.body, item.param_env), - |_, local| old_dataflow::DebugFormatted::new(&local), - ); - - let indirectly_mutable = - old_dataflow::DataflowResultsCursor::new(indirectly_mutable, *item.body); + // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not + // allowed in a const. + // + // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this + // without breaking stable code? + let indirectly_mutable = MaybeMutBorrowedLocals::mut_borrows_only(tcx, *body, param_env) + .unsound_ignore_borrow_on_drop() + .into_engine(tcx, *body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(*body); let qualifs = Qualifs { needs_drop, has_mut_interior, indirectly_mutable }; @@ -210,7 +213,7 @@ impl Validator<'a, 'mir, 'tcx> { // If an operation is supported in miri (and is not already controlled by a feature gate) it // can be turned on with `-Zunleash-the-miri-inside-of-you`. - let is_unleashable = O::IS_SUPPORTED_IN_MIRI && O::feature_gate(self.tcx).is_none(); + let is_unleashable = O::IS_SUPPORTED_IN_MIRI && O::feature_gate().is_none(); if is_unleashable && self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { self.tcx.sess.span_warn(span, "skipping const checks"); @@ -274,7 +277,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { } }; self.visit_place_base(&place.local, ctx, location); - self.visit_projection(&place.local, reborrowed_proj, ctx, location); + self.visit_projection(place.local, reborrowed_proj, ctx, location); return; } } @@ -287,7 +290,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf), }; self.visit_place_base(&place.local, ctx, location); - self.visit_projection(&place.local, reborrowed_proj, ctx, location); + self.visit_projection(place.local, reborrowed_proj, ctx, location); return; } } @@ -341,7 +344,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { Rvalue::Ref(_, BorrowKind::Shared, ref place) | Rvalue::Ref(_, BorrowKind::Shallow, ref place) | Rvalue::AddressOf(Mutability::Not, ref place) => { - let borrowed_place_has_mut_interior = HasMutInterior::in_place( + let borrowed_place_has_mut_interior = qualifs::in_place::( &self.item, &mut |local| self.qualifs.has_mut_interior(local, location), place.as_ref(), @@ -406,7 +409,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { } fn visit_projection_elem( &mut self, - place_local: &Local, + place_local: Local, proj_base: &[PlaceElem<'tcx>], elem: &PlaceElem<'tcx>, context: PlaceContext, @@ -426,11 +429,11 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { match elem { ProjectionElem::Deref => { - let base_ty = Place::ty_from(*place_local, proj_base, *self.body, self.tcx).ty; + let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty; if let ty::RawPtr(_) = base_ty.kind { if proj_base.is_empty() { if let (local, []) = (place_local, proj_base) { - let decl = &self.body.local_decls[*local]; + let decl = &self.body.local_decls[local]; if let LocalInfo::StaticRef { def_id, .. } = decl.local_info { let span = decl.source_info.span; self.check_static(def_id, span); @@ -450,7 +453,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { | ProjectionElem::Subslice { .. } | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - let base_ty = Place::ty_from(*place_local, proj_base, *self.body, self.tcx).ty; + let base_ty = Place::ty_from(place_local, proj_base, *self.body, self.tcx).ty; match base_ty.ty_adt_def() { Some(def) if def.is_union() => { self.check_op(ops::UnionAccess); @@ -500,8 +503,8 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { TerminatorKind::Call { func, .. } => { let fn_ty = func.ty(*self.body, self.tcx); - let def_id = match fn_ty.kind { - ty::FnDef(def_id, _) => def_id, + let (def_id, substs) = match fn_ty.kind { + ty::FnDef(def_id, substs) => (def_id, substs), ty::FnPtr(_) => { self.check_op(ops::FnCallIndirect); @@ -518,6 +521,20 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { return; } + // See if this is a trait method for a concrete type whose impl of that trait is + // `const`. + if self.tcx.features().const_trait_impl { + let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs); + debug!("Resolving ({:?}) -> {:?}", def_id, instance); + if let Some(func) = instance { + if let InstanceDef::Item(def_id) = func.def { + if is_const_fn(self.tcx, def_id) { + return; + } + } + } + } + if is_lang_panic_fn(self.tcx, def_id) { self.check_op(ops::Panic); } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) { diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 6e80338c975..437a154a9b8 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -1,5 +1,3 @@ -use rustc::hir::map::Map; -use rustc::lint::builtin::{SAFE_PACKED_BORROWS, UNUSED_UNSAFE}; use rustc::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc::mir::*; use rustc::ty::cast::CastTy; @@ -11,6 +9,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit; use rustc_hir::Node; +use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNUSED_UNSAFE}; use rustc_span::symbol::{sym, Symbol}; use std::ops::Bound; @@ -178,6 +177,16 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { + // prevent + // * `&mut x.field` + // * `x.field = y;` + // * `&x.field` if `field`'s type has interior mutability + // because either of these would allow modifying the layout constrained field and + // insert values that violate the layout constraints. + if context.is_mutating_use() || context.is_borrow() { + self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use()); + } + for (i, elem) in place.projection.iter().enumerate() { let proj_base = &place.projection[..i]; @@ -198,24 +207,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { ); } } - let is_borrow_of_interior_mut = context.is_borrow() - && !Place::ty_from(place.local, proj_base, self.body, self.tcx).ty.is_freeze( - self.tcx, - self.param_env, - self.source_info.span, - ); - // prevent - // * `&mut x.field` - // * `x.field = y;` - // * `&x.field` if `field`'s type has interior mutability - // because either of these would allow modifying the layout constrained field and - // insert values that violate the layout constraints. - if context.is_mutating_use() || is_borrow_of_interior_mut { - self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use()); - } let old_source_info = self.source_info; - if let (local, []) = (&place.local, proj_base) { - let decl = &self.body.local_decls[*local]; + if let [] = proj_base { + let decl = &self.body.local_decls[place.local]; if decl.internal { if let LocalInfo::StaticRef { def_id, .. } = decl.local_info { if self.tcx.is_mutable_static(def_id) { @@ -240,7 +234,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { // Internal locals are used in the `move_val_init` desugaring. // We want to check unsafety against the source info of the // desugaring, rather than the source info of the RHS. - self.source_info = self.body.local_decls[*local].source_info; + self.source_info = self.body.local_decls[place.local].source_info; } } } @@ -396,6 +390,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { cursor = proj_base; match elem { + // Modifications behind a dereference don't affect the value of + // the pointer. + ProjectionElem::Deref => return, ProjectionElem::Field(..) => { let ty = Place::ty_from(place.local, proj_base, &self.body.local_decls, self.tcx).ty; @@ -409,7 +406,14 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { "mutating layout constrained fields cannot statically be \ checked for valid values", ) - } else { + + // Check `is_freeze` as late as possible to avoid cycle errors + // with opaque types. + } else if !place.ty(self.body, self.tcx).ty.is_freeze( + self.tcx, + self.param_env, + self.source_info.span, + ) { ( "borrow of layout constrained field with interior \ mutability", @@ -417,6 +421,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { lose the constraints. Coupled with interior mutability, \ the field can be changed to invalid values", ) + } else { + continue; }; self.require_unsafe( description, @@ -444,9 +450,9 @@ struct UnusedUnsafeVisitor<'a> { } impl<'a, 'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'a> { - type Map = Map<'tcx>; + type Map = intravisit::ErasedMap<'tcx>; - fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, Self::Map> { + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { intravisit::NestedVisitorMap::None } @@ -637,7 +643,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { } } - let mut unsafe_blocks: Vec<_> = unsafe_blocks.into_iter().collect(); + let mut unsafe_blocks: Vec<_> = unsafe_blocks.iter().collect(); unsafe_blocks.sort_by_cached_key(|(hir_id, _)| tcx.hir().hir_to_node_id(*hir_id)); let used_unsafe: FxHashSet<_> = unsafe_blocks.iter().flat_map(|&&(id, used)| used.then_some(id)).collect(); diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index a7da4f7c164..ca23c44f646 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -4,29 +4,29 @@ use std::borrow::Cow; use std::cell::Cell; -use rustc::mir::interpret::{InterpResult, PanicInfo, Scalar}; +use rustc::mir::interpret::{InterpResult, Scalar}; use rustc::mir::visit::{ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, }; use rustc::mir::{ - read_only, AggregateKind, BasicBlock, BinOp, Body, BodyAndCache, ClearCrossCrate, Constant, - Local, LocalDecl, LocalKind, Location, Operand, Place, ReadOnlyBodyAndCache, Rvalue, + read_only, AggregateKind, AssertKind, BasicBlock, BinOp, Body, BodyAndCache, ClearCrossCrate, + Constant, Local, LocalDecl, LocalKind, Location, Operand, Place, ReadOnlyBodyAndCache, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement, StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE, }; -use rustc::traits; use rustc::ty::layout::{ HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout, }; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable}; +use rustc_ast::ast::Mutability; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; use rustc_hir::HirId; use rustc_index::vec::IndexVec; -use rustc_span::{Span, DUMMY_SP}; -use syntax::ast::Mutability; +use rustc_session::lint; +use rustc_span::Span; +use rustc_trait_selection::traits; use crate::const_eval::error_to_const_error; use crate::interpret::{ @@ -197,8 +197,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { fn assert_panic( _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _span: Span, - _msg: &rustc::mir::interpret::AssertMessage<'tcx>, + _msg: &rustc::mir::AssertMessage<'tcx>, _unwind: Option, ) -> InterpResult<'tcx> { bug!("panics terminators are not evaluated in ConstProp"); @@ -221,13 +220,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { )); } - fn find_foreign_static( - _tcx: TyCtxt<'tcx>, - _def_id: DefId, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { - throw_unsup!(ReadForeignStatic) - } - #[inline(always)] fn init_allocation_extra<'b>( _memory_extra: &(), @@ -278,10 +270,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { Ok(()) } - fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) - } - #[inline(always)] fn stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { Ok(()) @@ -292,7 +280,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine { struct ConstPropagator<'mir, 'tcx> { ecx: InterpCx<'mir, 'tcx, ConstPropMachine>, tcx: TyCtxt<'tcx>, - source: MirSource<'tcx>, can_const_prop: IndexVec, param_env: ParamEnv<'tcx>, // FIXME(eddyb) avoid cloning these two fields more than once, @@ -372,7 +359,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ConstPropagator { ecx, tcx, - source, param_env, can_const_prop, // FIXME(eddyb) avoid cloning these two fields more than once, @@ -410,57 +396,25 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } - fn use_ecx(&mut self, source_info: SourceInfo, f: F) -> Option + fn use_ecx(&mut self, f: F) -> Option where F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, { - self.ecx.tcx.span = source_info.span; - // FIXME(eddyb) move this to the `Panic(_)` error case, so that - // `f(self)` is always called, and that the only difference when the - // scope's `local_data` is missing, is that the lint isn't emitted. - let lint_root = self.lint_root(source_info)?; let r = match f(self) { Ok(val) => Some(val), Err(error) => { - use rustc::mir::interpret::{ - InterpError::*, UndefinedBehaviorInfo, UnsupportedOpInfo, - }; - match error.kind { - MachineStop(_) => bug!("ConstProp does not stop"), - - // Some error shouldn't come up because creating them causes - // an allocation, which we should avoid. When that happens, - // dedicated error variants should be introduced instead. - // Only test this in debug builds though to avoid disruptions. - Unsupported(UnsupportedOpInfo::Unsupported(_)) - | Unsupported(UnsupportedOpInfo::ValidationFailure(_)) - | UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) - | UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) - if cfg!(debug_assertions) => - { - bug!("const-prop encountered allocating error: {:?}", error.kind); - } - - Unsupported(_) - | UndefinedBehavior(_) - | InvalidProgram(_) - | ResourceExhaustion(_) => { - // Ignore these errors. - } - Panic(_) => { - let diagnostic = error_to_const_error(&self.ecx, error); - diagnostic.report_as_lint( - self.ecx.tcx, - "this expression will panic at runtime", - lint_root, - None, - ); - } - } + // Some errors shouldn't come up because creating them causes + // an allocation, which we should avoid. When that happens, + // dedicated error variants should be introduced instead. + // Only test this in debug builds though to avoid disruptions. + debug_assert!( + !error.kind.allocates(), + "const-prop encountered allocating error: {}", + error + ); None } }; - self.ecx.tcx.span = DUMMY_SP; r } @@ -504,37 +458,55 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } - fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option> { + fn eval_place(&mut self, place: &Place<'tcx>) -> Option> { trace!("eval_place(place={:?})", place); - self.use_ecx(source_info, |this| this.ecx.eval_place_to_op(place, None)) + self.use_ecx(|this| this.ecx.eval_place_to_op(place, None)) } fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option> { match *op { Operand::Constant(ref c) => self.eval_constant(c, source_info), - Operand::Move(ref place) | Operand::Copy(ref place) => { - self.eval_place(place, source_info) - } + Operand::Move(ref place) | Operand::Copy(ref place) => self.eval_place(place), } } + fn report_assert_as_lint( + &self, + lint: &'static lint::Lint, + source_info: SourceInfo, + message: &'static str, + panic: AssertKind, + ) -> Option<()> { + let lint_root = self.lint_root(source_info)?; + self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| { + let mut err = lint.build(message); + err.span_label(source_info.span, format!("{:?}", panic)); + err.emit() + }); + return None; + } + fn check_unary_op( &mut self, op: UnOp, arg: &Operand<'tcx>, source_info: SourceInfo, ) -> Option<()> { - self.use_ecx(source_info, |this| { + if self.use_ecx(|this| { let val = this.ecx.read_immediate(this.ecx.eval_operand(arg, None)?)?; let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, val)?; - - if overflow { - assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow"); - throw_panic!(OverflowNeg); - } - - Ok(()) - })?; + Ok(overflow) + })? { + // `AssertKind` only has an `OverflowNeg` variant, so make sure that is + // appropriate to use. + assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow"); + self.report_assert_as_lint( + lint::builtin::ARITHMETIC_OVERFLOW, + source_info, + "this arithmetic operation will overflow", + AssertKind::OverflowNeg, + )?; + } Some(()) } @@ -545,46 +517,41 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { left: &Operand<'tcx>, right: &Operand<'tcx>, source_info: SourceInfo, - place_layout: TyLayout<'tcx>, - overflow_check: bool, ) -> Option<()> { - let r = self.use_ecx(source_info, |this| { - this.ecx.read_immediate(this.ecx.eval_operand(right, None)?) - })?; + let r = + self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?))?; + // Check for exceeding shifts *even if* we cannot evaluate the LHS. if op == BinOp::Shr || op == BinOp::Shl { - let left_bits = place_layout.size.bits(); + // We need the type of the LHS. We cannot use `place_layout` as that is the type + // of the result, which for checked binops is not the same! + let left_ty = left.ty(&self.local_decls, self.tcx); + let left_size_bits = self.ecx.layout_of(left_ty).ok()?.size.bits(); let right_size = r.layout.size; - let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size)); - if r_bits.map_or(false, |b| b >= left_bits as u128) { - let lint_root = self.lint_root(source_info)?; - self.tcx.struct_span_lint_hir( - ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, - lint_root, - source_info.span, - |lint| { - let dir = if op == BinOp::Shr { "right" } else { "left" }; - lint.build(&format!("attempt to shift {} with overflow", dir)).emit() - }, - ); - return None; + let r_bits = r.to_scalar().ok(); + // This is basically `force_bits`. + let r_bits = r_bits.and_then(|r| r.to_bits_or_ptr(right_size, &self.tcx).ok()); + if r_bits.map_or(false, |b| b >= left_size_bits as u128) { + self.report_assert_as_lint( + lint::builtin::ARITHMETIC_OVERFLOW, + source_info, + "this arithmetic operation will overflow", + AssertKind::Overflow(op), + )?; } } - // If overflow checking is enabled (like in debug mode by default), - // then we'll already catch overflow when we evaluate the `Assert` statement - // in MIR. However, if overflow checking is disabled, then there won't be any - // `Assert` statement and so we have to do additional checking here. - if !overflow_check { - self.use_ecx(source_info, |this| { - let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; - let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?; - - if overflow { - throw_panic!(Overflow(op)); - } - - Ok(()) - })?; + // The remaining operators are handled through `overflowing_binary_op`. + if self.use_ecx(|this| { + let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; + let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?; + Ok(overflow) + })? { + self.report_assert_as_lint( + lint::builtin::ARITHMETIC_OVERFLOW, + source_info, + "this arithmetic operation will overflow", + AssertKind::Overflow(op), + )?; } Some(()) @@ -607,8 +574,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } - let overflow_check = self.tcx.sess.overflow_checks(); - // Perform any special handling for specific Rvalue types. // Generally, checks here fall into one of two categories: // 1. Additional checking to provide useful lints to the user @@ -617,19 +582,26 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // 2. Working around bugs in other parts of the compiler // - In this case, we'll return `None` from this function to stop evaluation. match rvalue { - // Additional checking: if overflow checks are disabled (which is usually the case in - // release mode), then we need to do additional checking here to give lints to the user - // if an overflow would occur. - Rvalue::UnaryOp(op, arg) if !overflow_check => { + // Additional checking: give lints to the user if an overflow would occur. + // We do this here and not in the `Assert` terminator as that terminator is + // only sometimes emitted (overflow checks can be disabled), but we want to always + // lint. + Rvalue::UnaryOp(op, arg) => { trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg); self.check_unary_op(*op, arg, source_info)?; } - - // Additional checking: check for overflows on integer binary operations and report - // them to the user as lints. Rvalue::BinaryOp(op, left, right) => { trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right); - self.check_binary_op(*op, left, right, source_info, place_layout, overflow_check)?; + self.check_binary_op(*op, left, right, source_info)?; + } + Rvalue::CheckedBinaryOp(op, left, right) => { + trace!( + "checking CheckedBinaryOp(op = {:?}, left = {:?}, right = {:?})", + op, + left, + right + ); + self.check_binary_op(*op, left, right, source_info)?; } // Do not try creating references (#67862) @@ -642,7 +614,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { _ => {} } - self.use_ecx(source_info, |this| { + self.use_ecx(|this| { trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place); this.ecx.eval_rvalue_into_place(rvalue, place)?; Ok(()) @@ -664,18 +636,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { source_info: SourceInfo, ) { trace!("attepting to replace {:?} with {:?}", rval, value); - if let Err(e) = self.ecx.validate_operand( + if let Err(e) = self.ecx.const_validate_operand( value, vec![], // FIXME: is ref tracking too expensive? - Some(&mut interpret::RefTracking::empty()), + &mut interpret::RefTracking::empty(), + /*may_ref_to_static*/ true, ) { trace!("validation error, attempt failed: {:?}", e); return; } - // FIXME> figure out what tho do when try_read_immediate fails - let imm = self.use_ecx(source_info, |this| this.ecx.try_read_immediate(value)); + // FIXME> figure out what to do when try_read_immediate fails + let imm = self.use_ecx(|this| this.ecx.try_read_immediate(value)); if let Some(Ok(imm)) = imm { match *imm { @@ -698,7 +671,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { if let ty::Tuple(substs) = ty { // Only do it if tuple is also a pair with two scalars if substs.len() == 2 { - let opt_ty1_ty2 = self.use_ecx(source_info, |this| { + let opt_ty1_ty2 = self.use_ecx(|this| { let ty1 = substs[0].expect_ty(); let ty2 = substs[1].expect_ty(); let ty_is_scalar = |ty| { @@ -908,54 +881,39 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { } Operand::Constant(_) => {} } - let span = terminator.source_info.span; - let hir_id = self - .tcx - .hir() - .as_local_hir_id(self.source.def_id()) - .expect("some part of a failing const eval must be local"); - self.tcx.struct_span_lint_hir( - ::rustc::lint::builtin::CONST_ERR, - hir_id, - span, - |lint| { - let msg = match msg { - PanicInfo::Overflow(_) - | PanicInfo::OverflowNeg - | PanicInfo::DivisionByZero - | PanicInfo::RemainderByZero => msg.description().to_owned(), - PanicInfo::BoundsCheck { ref len, ref index } => { - let len = self - .eval_operand(len, source_info) - .expect("len must be const"); - let len = match self.ecx.read_scalar(len) { - Ok(ScalarMaybeUndef::Scalar(Scalar::Raw { - data, - .. - })) => data, - other => bug!("const len not primitive: {:?}", other), - }; - let index = self - .eval_operand(index, source_info) - .expect("index must be const"); - let index = match self.ecx.read_scalar(index) { - Ok(ScalarMaybeUndef::Scalar(Scalar::Raw { - data, - .. - })) => data, - other => bug!("const index not primitive: {:?}", other), - }; - format!( - "index out of bounds: \ - the len is {} but the index is {}", - len, index, - ) - } - // Need proper const propagator for these - _ => return, - }; - lint.build(&msg).emit() - }, + let msg = match msg { + AssertKind::DivisionByZero => AssertKind::DivisionByZero, + AssertKind::RemainderByZero => AssertKind::RemainderByZero, + AssertKind::BoundsCheck { ref len, ref index } => { + let len = + self.eval_operand(len, source_info).expect("len must be const"); + let len = self + .ecx + .read_scalar(len) + .unwrap() + .to_machine_usize(&self.tcx) + .unwrap(); + let index = self + .eval_operand(index, source_info) + .expect("index must be const"); + let index = self + .ecx + .read_scalar(index) + .unwrap() + .to_machine_usize(&self.tcx) + .unwrap(); + AssertKind::BoundsCheck { len, index } + } + // Overflow is are already covered by checks on the binary operators. + AssertKind::Overflow(_) | AssertKind::OverflowNeg => return, + // Need proper const propagator for these. + _ => return, + }; + self.report_assert_as_lint( + lint::builtin::UNCONDITIONAL_PANIC, + source_info, + "this operation will panic at runtime", + msg, ); } else { if self.should_const_prop(value) { diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 5dec2c6df99..795bcb57d06 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -8,8 +8,8 @@ use std::io; use crate::transform::{MirPass, MirSource}; use crate::util as mir_util; use rustc::mir::{Body, BodyAndCache}; -use rustc::session::config::{OutputFilenames, OutputType}; use rustc::ty::TyCtxt; +use rustc_session::config::{OutputFilenames, OutputType}; pub struct Marker(pub &'static str); diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 99f13f68cbc..5d02074aaaa 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -1,8 +1,8 @@ use crate::dataflow; -use crate::dataflow::generic::{Analysis, Results}; +use crate::dataflow::generic::{Analysis, ResultsCursor}; use crate::dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; +use crate::dataflow::on_lookup_result_bits; use crate::dataflow::MoveDataParamEnv; -use crate::dataflow::{drop_flag_effects_for_location, on_lookup_result_bits}; use crate::dataflow::{on_all_children_bits, on_all_drop_children_bits}; use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; use crate::transform::{MirPass, MirSource}; @@ -41,22 +41,23 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { let env = MoveDataParamEnv { move_data, param_env }; let dead_unwinds = find_dead_unwinds(tcx, body, def_id, &env); - let flow_inits = MaybeInitializedPlaces::new(tcx, body, &env) + let inits = MaybeInitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body, def_id) .dead_unwinds(&dead_unwinds) - .iterate_to_fixpoint(); + .iterate_to_fixpoint() + .into_results_cursor(body); - let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &env) + let uninits = MaybeUninitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body, def_id) .dead_unwinds(&dead_unwinds) - .iterate_to_fixpoint(); + .iterate_to_fixpoint() + .into_results_cursor(body); ElaborateDropsCtxt { tcx, body, env: &env, - flow_inits, - flow_uninits, + init_data: InitializationData { inits, uninits }, drop_flags: Default::default(), patch: MirPatch::new(body), } @@ -79,9 +80,10 @@ fn find_dead_unwinds<'tcx>( // We only need to do this pass once, because unwind edges can only // reach cleanup blocks, which can't have unwind edges themselves. let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); - let flow_inits = MaybeInitializedPlaces::new(tcx, body, &env) + let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body, def_id) - .iterate_to_fixpoint(); + .iterate_to_fixpoint() + .into_results_cursor(body); for (bb, bb_data) in body.basic_blocks().iter_enumerated() { let location = match bb_data.terminator().kind { TerminatorKind::Drop { ref location, unwind: Some(_), .. } @@ -89,15 +91,7 @@ fn find_dead_unwinds<'tcx>( _ => continue, }; - let mut init_data = InitializationData { - live: flow_inits.entry_set_for_block(bb).clone(), - dead: BitSet::new_empty(env.move_data.move_paths.len()), - }; - debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}", bb, bb_data, init_data.live); - for stmt in 0..bb_data.statements.len() { - let loc = Location { block: bb, statement_index: stmt }; - init_data.apply_location(tcx, body, env, loc); - } + debug!("find_dead_unwinds @ {:?}: {:?}", bb, bb_data); let path = match env.move_data.rev_lookup.find(location.as_ref()) { LookupResult::Exact(e) => e, @@ -107,12 +101,18 @@ fn find_dead_unwinds<'tcx>( } }; - debug!("find_dead_unwinds @ {:?}: path({:?})={:?}", bb, location, path); + flow_inits.seek_before(body.terminator_loc(bb)); + debug!( + "find_dead_unwinds @ {:?}: path({:?})={:?}; init_data={:?}", + bb, + location, + path, + flow_inits.get() + ); let mut maybe_live = false; on_all_drop_children_bits(tcx, body, &env, path, |child| { - let (child_maybe_live, _) = init_data.state(child); - maybe_live |= child_maybe_live; + maybe_live |= flow_inits.contains(child); }); debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live); @@ -124,41 +124,23 @@ fn find_dead_unwinds<'tcx>( dead_unwinds } -struct InitializationData { - live: BitSet, - dead: BitSet, +struct InitializationData<'mir, 'tcx> { + inits: ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, + uninits: ResultsCursor<'mir, 'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>, } -impl InitializationData { - fn apply_location<'tcx>( - &mut self, - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - env: &MoveDataParamEnv<'tcx>, - loc: Location, - ) { - drop_flag_effects_for_location(tcx, body, env, loc, |path, df| { - debug!("at location {:?}: setting {:?} to {:?}", loc, path, df); - match df { - DropFlagState::Present => { - self.live.insert(path); - self.dead.remove(path); - } - DropFlagState::Absent => { - self.dead.insert(path); - self.live.remove(path); - } - } - }); +impl InitializationData<'_, '_> { + fn seek_before(&mut self, loc: Location) { + self.inits.seek_before(loc); + self.uninits.seek_before(loc); } - fn state(&self, path: MovePathIndex) -> (bool, bool) { - (self.live.contains(path), self.dead.contains(path)) + fn maybe_live_dead(&self, path: MovePathIndex) -> (bool, bool) { + (self.inits.contains(path), self.uninits.contains(path)) } } struct Elaborator<'a, 'b, 'tcx> { - init_data: &'a InitializationData, ctxt: &'a mut ElaborateDropsCtxt<'b, 'tcx>, } @@ -189,13 +171,13 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle { let ((maybe_live, maybe_dead), multipart) = match mode { - DropFlagMode::Shallow => (self.init_data.state(path), false), + DropFlagMode::Shallow => (self.ctxt.init_data.maybe_live_dead(path), false), DropFlagMode::Deep => { let mut some_live = false; let mut some_dead = false; let mut children_count = 0; on_all_drop_children_bits(self.tcx(), self.body(), self.ctxt.env, path, |child| { - let (live, dead) = self.init_data.state(child); + let (live, dead) = self.ctxt.init_data.maybe_live_dead(child); debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead)); some_live |= live; some_dead |= dead; @@ -269,8 +251,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, env: &'a MoveDataParamEnv<'tcx>, - flow_inits: Results<'tcx, MaybeInitializedPlaces<'a, 'tcx>>, - flow_uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'tcx>>, + init_data: InitializationData<'a, 'tcx>, drop_flags: FxHashMap, patch: MirPatch<'tcx>, } @@ -284,25 +265,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.env.param_env } - // FIXME(ecstaticmorse): This duplicates `dataflow::ResultsCursor` but hardcodes the transfer - // function for `Maybe{Un,}InitializedPlaces` directly. It should be replaced by a a pair of - // `ResultsCursor`s. - fn initialization_data_at(&self, loc: Location) -> InitializationData { - let mut data = InitializationData { - live: self.flow_inits.entry_set_for_block(loc.block).to_owned(), - dead: self.flow_uninits.entry_set_for_block(loc.block).to_owned(), - }; - for stmt in 0..loc.statement_index { - data.apply_location( - self.tcx, - self.body, - self.env, - Location { block: loc.block, statement_index: stmt }, - ); - } - data - } - fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) { let tcx = self.tcx; let patch = &mut self.patch; @@ -338,10 +300,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { _ => continue, }; - let init_data = self.initialization_data_at(Location { - block: bb, - statement_index: data.statements.len(), - }); + self.init_data.seek_before(self.body.terminator_loc(bb)); let path = self.move_data().rev_lookup.find(location.as_ref()); debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, location, path); @@ -350,7 +309,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { LookupResult::Exact(e) => e, LookupResult::Parent(None) => continue, LookupResult::Parent(Some(parent)) => { - let (_maybe_live, maybe_dead) = init_data.state(parent); + let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent); if maybe_dead { span_bug!( terminator.source_info.span, @@ -365,7 +324,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { }; on_all_drop_children_bits(self.tcx, self.body, self.env, path, |child| { - let (maybe_live, maybe_dead) = init_data.state(child); + let (maybe_live, maybe_dead) = self.init_data.maybe_live_dead(child); debug!( "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", child, @@ -388,10 +347,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let resume_block = self.patch.resume_block(); match terminator.kind { TerminatorKind::Drop { ref location, target, unwind } => { - let init_data = self.initialization_data_at(loc); + self.init_data.seek_before(loc); match self.move_data().rev_lookup.find(location.as_ref()) { LookupResult::Exact(path) => elaborate_drop( - &mut Elaborator { init_data: &init_data, ctxt: self }, + &mut Elaborator { ctxt: self }, terminator.source_info, location, path, @@ -471,10 +430,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { match self.move_data().rev_lookup.find(location.as_ref()) { LookupResult::Exact(path) => { debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path); - let init_data = self.initialization_data_at(loc); - + self.init_data.seek_before(loc); elaborate_drop( - &mut Elaborator { init_data: &init_data, ctxt: self }, + &mut Elaborator { ctxt: self }, terminator.source_info, location, path, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index a6fc6573178..b2906739ff1 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -49,9 +49,8 @@ //! For generators with state 1 (returned) and state 2 (poisoned) it does nothing. //! Otherwise it drops all the values in scope at the last suspension point. -use crate::dataflow::{do_dataflow, DataflowResultsCursor, DebugFormatted}; -use crate::dataflow::{DataflowResults, DataflowResultsConsumer, FlowAtLocation}; -use crate::dataflow::{HaveBeenBorrowedLocals, MaybeStorageLive, RequiresStorage}; +use crate::dataflow::generic::{self as dataflow, Analysis}; +use crate::dataflow::{MaybeBorrowedLocals, MaybeRequiresStorage, MaybeStorageLive}; use crate::transform::no_landing_pads::no_landing_pads; use crate::transform::simplify; use crate::transform::{MirPass, MirSource}; @@ -108,15 +107,15 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> { } fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { - assert_ne!(*local, self_arg()); + assert_ne!(*local, SELF_ARG); } fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if place.local == self_arg() { + if place.local == SELF_ARG { replace_base( place, Place { - local: self_arg(), + local: SELF_ARG, projection: self.tcx().intern_place_elems(&[ProjectionElem::Deref]), }, self.tcx, @@ -126,7 +125,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> { for elem in place.projection.iter() { if let PlaceElem::Index(local) = elem { - assert_ne!(*local, self_arg()); + assert_ne!(*local, SELF_ARG); } } } @@ -144,15 +143,15 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { } fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { - assert_ne!(*local, self_arg()); + assert_ne!(*local, SELF_ARG); } fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) { - if place.local == self_arg() { + if place.local == SELF_ARG { replace_base( place, Place { - local: self_arg(), + local: SELF_ARG, projection: self.tcx().intern_place_elems(&[ProjectionElem::Field( Field::new(0), self.ref_gen_ty, @@ -165,7 +164,7 @@ impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> { for elem in place.projection.iter() { if let PlaceElem::Index(local) = elem { - assert_ne!(*local, self_arg()); + assert_ne!(*local, SELF_ARG); } } } @@ -181,22 +180,26 @@ fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtx place.projection = tcx.intern_place_elems(&new_projection); } -fn self_arg() -> Local { - Local::new(1) -} +const SELF_ARG: Local = Local::from_u32(1); -/// Generator have not been resumed yet +/// Generator has not been resumed yet. const UNRESUMED: usize = GeneratorSubsts::UNRESUMED; -/// Generator has returned / is completed +/// Generator has returned / is completed. const RETURNED: usize = GeneratorSubsts::RETURNED; -/// Generator has been poisoned +/// Generator has panicked and is poisoned. const POISONED: usize = GeneratorSubsts::POISONED; +/// A `yield` point in the generator. struct SuspensionPoint<'tcx> { + /// State discriminant used when suspending or resuming at this point. state: usize, + /// The block to jump to after resumption. resume: BasicBlock, + /// Where to move the resume argument after resumption. resume_arg: Place<'tcx>, + /// Which block to jump to if the generator is dropped in this state. drop: Option, + /// Set of locals that have live storage while at this suspension point. storage_liveness: liveness::LiveVarSet, } @@ -232,7 +235,7 @@ impl TransformVisitor<'tcx> { // Create a Place referencing a generator struct field fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> { - let self_place = Place::from(self_arg()); + let self_place = Place::from(SELF_ARG); let base = self.tcx.mk_place_downcast_unnamed(self_place, variant_index); let mut projection = base.projection.to_vec(); projection.push(ProjectionElem::Field(Field::new(idx), ty)); @@ -242,7 +245,7 @@ impl TransformVisitor<'tcx> { // Create a statement which changes the discriminant fn set_discr(&self, state_disc: VariantIdx, source_info: SourceInfo) -> Statement<'tcx> { - let self_place = Place::from(self_arg()); + let self_place = Place::from(SELF_ARG); Statement { source_info, kind: StatementKind::SetDiscriminant { @@ -258,7 +261,7 @@ impl TransformVisitor<'tcx> { let local_decls_len = body.local_decls.push(temp_decl); let temp = Place::from(local_decls_len); - let self_place = Place::from(self_arg()); + let self_place = Place::from(SELF_ARG); let assign = Statement { source_info: source_info(body), kind: StatementKind::Assign(box (temp, Rvalue::Discriminant(self_place))), @@ -324,6 +327,15 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { // Yield let state = 3 + self.suspension_points.len(); + // The resume arg target location might itself be remapped if its base local is + // live across a yield. + let resume_arg = + if let Some(&(ty, variant, idx)) = self.remap.get(&resume_arg.local) { + self.make_field(variant, idx, ty) + } else { + resume_arg + }; + self.suspension_points.push(SuspensionPoint { state, resume, @@ -451,18 +463,15 @@ fn locals_live_across_suspend_points( source: MirSource<'tcx>, movable: bool, ) -> LivenessInfo { - let dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); let def_id = source.def_id(); let body_ref: &Body<'_> = &body; // Calculate when MIR locals have live storage. This gives us an upper bound of their // lifetimes. - let storage_live_analysis = MaybeStorageLive::new(body_ref); - let storage_live_results = - do_dataflow(tcx, body_ref, def_id, &[], &dead_unwinds, storage_live_analysis, |bd, p| { - DebugFormatted::new(&bd.body().local_decls[p]) - }); - let mut storage_live_cursor = DataflowResultsCursor::new(&storage_live_results, body_ref); + let mut storage_live = MaybeStorageLive + .into_engine(tcx, body_ref, def_id) + .iterate_to_fixpoint() + .into_results_cursor(body_ref); // Find the MIR locals which do not use StorageLive/StorageDead statements. // The storage of these locals are always live. @@ -471,32 +480,19 @@ fn locals_live_across_suspend_points( // Calculate the MIR locals which have been previously // borrowed (even if they are still active). - let borrowed_locals_analysis = HaveBeenBorrowedLocals::new(body_ref); - let borrowed_locals_results = do_dataflow( - tcx, - body_ref, - def_id, - &[], - &dead_unwinds, - borrowed_locals_analysis, - |bd, p| DebugFormatted::new(&bd.body().local_decls[p]), - ); - let mut borrowed_locals_cursor = DataflowResultsCursor::new(&borrowed_locals_results, body_ref); + let borrowed_locals_results = + MaybeBorrowedLocals::all_borrows().into_engine(tcx, body_ref, def_id).iterate_to_fixpoint(); + + let mut borrowed_locals_cursor = + dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results); // Calculate the MIR locals that we actually need to keep storage around // for. - let requires_storage_analysis = RequiresStorage::new(body, &borrowed_locals_results); - let requires_storage_results = do_dataflow( - tcx, - body_ref, - def_id, - &[], - &dead_unwinds, - requires_storage_analysis, - |bd, p| DebugFormatted::new(&bd.body().local_decls[p]), - ); + let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results) + .into_engine(tcx, body_ref, def_id) + .iterate_to_fixpoint(); let mut requires_storage_cursor = - DataflowResultsCursor::new(&requires_storage_results, body_ref); + dataflow::ResultsCursor::new(body_ref, &requires_storage_results); // Calculate the liveness of MIR locals ignoring borrows. let mut live_locals = liveness::LiveVarSet::new_empty(body.local_decls.len()); @@ -508,7 +504,7 @@ fn locals_live_across_suspend_points( for (block, data) in body.basic_blocks().iter_enumerated() { if let TerminatorKind::Yield { .. } = data.terminator().kind { - let loc = Location { block: block, statement_index: data.statements.len() }; + let loc = Location { block, statement_index: data.statements.len() }; if !movable { // The `liveness` variable contains the liveness of MIR locals ignoring borrows. @@ -521,18 +517,18 @@ fn locals_live_across_suspend_points( // If a borrow is converted to a raw reference, we must also assume that it lives // forever. Note that the final liveness is still bounded by the storage liveness // of the local, which happens using the `intersect` operation below. - borrowed_locals_cursor.seek(loc); + borrowed_locals_cursor.seek_before(loc); liveness.outs[block].union(borrowed_locals_cursor.get()); } - storage_live_cursor.seek(loc); - let storage_liveness = storage_live_cursor.get(); + storage_live.seek_before(loc); + let storage_liveness = storage_live.get(); // Store the storage liveness for later use so we can restore the state // after a suspension point storage_liveness_map.insert(block, storage_liveness.clone()); - requires_storage_cursor.seek(loc); + requires_storage_cursor.seek_before(loc); let storage_required = requires_storage_cursor.get().clone(); // Locals live are live at this point only if they are used across @@ -541,8 +537,8 @@ fn locals_live_across_suspend_points( let mut live_locals_here = storage_required; live_locals_here.intersect(&liveness.outs[block]); - // The generator argument is ignored - live_locals_here.remove(self_arg()); + // The generator argument is ignored. + live_locals_here.remove(SELF_ARG); debug!("loc = {:?}, live_locals_here = {:?}", loc, live_locals_here); @@ -602,7 +598,7 @@ fn compute_storage_conflicts( body: &'mir Body<'tcx>, stored_locals: &liveness::LiveVarSet, ignored: &StorageIgnored, - requires_storage: DataflowResults<'tcx, RequiresStorage<'mir, 'tcx>>, + requires_storage: dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, ) -> BitMatrix { assert_eq!(body.local_decls.len(), ignored.0.domain_size()); assert_eq!(body.local_decls.len(), stored_locals.domain_size()); @@ -620,8 +616,11 @@ fn compute_storage_conflicts( stored_locals: &stored_locals, local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()), }; - let mut state = FlowAtLocation::new(requires_storage); - visitor.analyze_results(&mut state); + + // Visit only reachable basic blocks. The exact order is not important. + let reachable_blocks = traversal::preorder(body).map(|(bb, _)| bb); + requires_storage.visit_with(body, reachable_blocks, &mut visitor); + let local_conflicts = visitor.local_conflicts; // Compress the matrix using only stored locals (Local -> GeneratorSavedLocal). @@ -650,60 +649,45 @@ fn compute_storage_conflicts( storage_conflicts } -struct StorageConflictVisitor<'body, 'tcx, 's> { - body: &'body Body<'tcx>, +struct StorageConflictVisitor<'mir, 'tcx, 's> { + body: &'mir Body<'tcx>, stored_locals: &'s liveness::LiveVarSet, // FIXME(tmandry): Consider using sparse bitsets here once we have good // benchmarks for generators. local_conflicts: BitMatrix, } -impl<'body, 'tcx, 's> DataflowResultsConsumer<'body, 'tcx> - for StorageConflictVisitor<'body, 'tcx, 's> -{ - type FlowState = FlowAtLocation<'tcx, RequiresStorage<'body, 'tcx>>; +impl dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> { + type FlowState = BitSet; - fn body(&self) -> &'body Body<'tcx> { - self.body - } - - fn visit_block_entry(&mut self, block: BasicBlock, flow_state: &Self::FlowState) { - // statement_index is only used for logging, so this is fine. - self.apply_state(flow_state, Location { block, statement_index: 0 }); - } - - fn visit_statement_entry( + fn visit_statement( &mut self, + state: &Self::FlowState, + _statement: &'mir Statement<'tcx>, loc: Location, - _stmt: &Statement<'tcx>, - flow_state: &Self::FlowState, ) { - self.apply_state(flow_state, loc); + self.apply_state(state, loc); } - fn visit_terminator_entry( + fn visit_terminator( &mut self, + state: &Self::FlowState, + _terminator: &'mir Terminator<'tcx>, loc: Location, - _term: &Terminator<'tcx>, - flow_state: &Self::FlowState, ) { - self.apply_state(flow_state, loc); + self.apply_state(state, loc); } } impl<'body, 'tcx, 's> StorageConflictVisitor<'body, 'tcx, 's> { - fn apply_state( - &mut self, - flow_state: &FlowAtLocation<'tcx, RequiresStorage<'body, 'tcx>>, - loc: Location, - ) { + fn apply_state(&mut self, flow_state: &BitSet, loc: Location) { // Ignore unreachable blocks. match self.body.basic_blocks()[loc.block].terminator().kind { TerminatorKind::Unreachable => return, _ => (), }; - let mut eligible_storage_live = flow_state.as_dense().clone(); + let mut eligible_storage_live = flow_state.clone(); eligible_storage_live.intersect(&self.stored_locals); for local in eligible_storage_live.iter() { @@ -851,7 +835,6 @@ fn elaborate_generator_drops<'tcx>( // generator's resume function. let param_env = tcx.param_env(def_id); - let gen = self_arg(); let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, param_env }; @@ -859,7 +842,7 @@ fn elaborate_generator_drops<'tcx>( let (target, unwind, source_info) = match block_data.terminator() { Terminator { source_info, kind: TerminatorKind::Drop { location, target, unwind } } => { if let Some(local) = location.as_local() { - if local == gen { + if local == SELF_ARG { (target, unwind, source_info) } else { continue; @@ -878,7 +861,7 @@ fn elaborate_generator_drops<'tcx>( elaborate_drop( &mut elaborator, *source_info, - &Place::from(gen), + &Place::from(SELF_ARG), (), *target, unwind, @@ -932,7 +915,7 @@ fn create_generator_drop_shim<'tcx>( make_generator_state_argument_indirect(tcx, def_id, &mut body); // Change the generator argument from &mut to *mut - body.local_decls[self_arg()] = LocalDecl { + body.local_decls[SELF_ARG] = LocalDecl { mutability: Mutability::Mut, ty: tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }), user_ty: UserTypeProjections::none(), @@ -947,7 +930,7 @@ fn create_generator_drop_shim<'tcx>( 0, Statement { source_info, - kind: StatementKind::Retag(RetagKind::Raw, box Place::from(self_arg())), + kind: StatementKind::Retag(RetagKind::Raw, box Place::from(SELF_ARG)), }, ) } @@ -958,7 +941,7 @@ fn create_generator_drop_shim<'tcx>( // unrelated code from the resume part of the function simplify::remove_dead_blocks(&mut body); - dump_mir(tcx, None, "generator_drop", &0, source, &mut body, |_, _| Ok(())); + dump_mir(tcx, None, "generator_drop", &0, source, &body, |_, _| Ok(())); body } @@ -1005,32 +988,127 @@ fn insert_panic_block<'tcx>( assert_block } +fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { + // Returning from a function with an uninhabited return type is undefined behavior. + if body.return_ty().conservative_is_privately_uninhabited(tcx) { + return false; + } + + // If there's a return terminator the function may return. + for block in body.basic_blocks() { + if let TerminatorKind::Return = block.terminator().kind { + return true; + } + } + + // Otherwise the function can't return. + false +} + +fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool { + // Nothing can unwind when landing pads are off. + if tcx.sess.no_landing_pads() { + return false; + } + + // Unwinds can only start at certain terminators. + for block in body.basic_blocks() { + match block.terminator().kind { + // These never unwind. + TerminatorKind::Goto { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdges { .. } + | TerminatorKind::FalseUnwind { .. } => {} + + // Resume will *continue* unwinding, but if there's no other unwinding terminator it + // will never be reached. + TerminatorKind::Resume => {} + + TerminatorKind::Yield { .. } => { + unreachable!("`can_unwind` called before generator transform") + } + + // These may unwind. + TerminatorKind::Drop { .. } + | TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Call { .. } + | TerminatorKind::Assert { .. } => return true, + } + } + + // If we didn't find an unwinding terminator, the function cannot unwind. + false +} + fn create_generator_resume_function<'tcx>( tcx: TyCtxt<'tcx>, transform: TransformVisitor<'tcx>, def_id: DefId, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>, + can_return: bool, ) { + let can_unwind = can_unwind(tcx, body); + // Poison the generator when it unwinds - for block in body.basic_blocks_mut() { - let source_info = block.terminator().source_info; - if let &TerminatorKind::Resume = &block.terminator().kind { - block.statements.push(transform.set_discr(VariantIdx::new(POISONED), source_info)); + if can_unwind { + let poison_block = BasicBlock::new(body.basic_blocks().len()); + let source_info = source_info(body); + body.basic_blocks_mut().push(BasicBlockData { + statements: vec![transform.set_discr(VariantIdx::new(POISONED), source_info)], + terminator: Some(Terminator { source_info, kind: TerminatorKind::Resume }), + is_cleanup: true, + }); + + for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() { + let source_info = block.terminator().source_info; + + if let TerminatorKind::Resume = block.terminator().kind { + // An existing `Resume` terminator is redirected to jump to our dedicated + // "poisoning block" above. + if idx != poison_block { + *block.terminator_mut() = Terminator { + source_info, + kind: TerminatorKind::Goto { target: poison_block }, + }; + } + } else if !block.is_cleanup { + // Any terminators that *can* unwind but don't have an unwind target set are also + // pointed at our poisoning block (unless they're part of the cleanup path). + if let Some(unwind @ None) = block.terminator_mut().unwind_mut() { + *unwind = Some(poison_block); + } + } } } let mut cases = create_cases(body, &transform, Operation::Resume); - use rustc::mir::interpret::PanicInfo::{ResumedAfterPanic, ResumedAfterReturn}; + use rustc::mir::AssertKind::{ResumedAfterPanic, ResumedAfterReturn}; // Jump to the entry point on the unresumed cases.insert(0, (UNRESUMED, BasicBlock::new(0))); // Panic when resumed on the returned or poisoned state let generator_kind = body.generator_kind.unwrap(); - cases.insert(1, (RETURNED, insert_panic_block(tcx, body, ResumedAfterReturn(generator_kind)))); - cases.insert(2, (POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(generator_kind)))); + + if can_unwind { + cases.insert( + 1, + (POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(generator_kind))), + ); + } + + if can_return { + cases.insert( + 1, + (RETURNED, insert_panic_block(tcx, body, ResumedAfterReturn(generator_kind))), + ); + } insert_switch(body, cases, &transform, TerminatorKind::Unreachable); @@ -1056,7 +1134,7 @@ fn insert_clean_drop(body: &mut BodyAndCache<'_>) -> BasicBlock { // Create a block to destroy an unresumed generators. This can only destroy upvars. let drop_clean = BasicBlock::new(body.basic_blocks().len()); let term = TerminatorKind::Drop { - location: Place::from(self_arg()), + location: Place::from(SELF_ARG), target: return_block, unwind: None, }; @@ -1214,6 +1292,8 @@ impl<'tcx> MirPass<'tcx> for StateTransform { let (remap, layout, storage_liveness) = compute_layout(tcx, source, &upvars, interior, movable, body); + let can_return = can_return(tcx, body); + // Run the transformation which converts Places from Local to generator struct // accesses for locals in `remap`. // It also rewrites `return x` and `yield y` as writing a new generator state and returning @@ -1257,6 +1337,6 @@ impl<'tcx> MirPass<'tcx> for StateTransform { body.generator_drop = Some(box drop_shim); // Create the Generator::resume function - create_generator_resume_function(tcx, transform, def_id, source, body); + create_generator_resume_function(tcx, transform, def_id, source, body, can_return); } } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index b6802505df7..769f3fdcc01 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -1,25 +1,22 @@ //! Inlining pass for MIR functions -use rustc_hir::def_id::DefId; - -use rustc_index::bit_set::BitSet; -use rustc_index::vec::{Idx, IndexVec}; - use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc::mir::visit::*; use rustc::mir::*; -use rustc::session::config::Sanitizer; use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable}; +use rustc_attr as attr; +use rustc_hir::def_id::DefId; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_session::config::Sanitizer; +use rustc_target::spec::abi::Abi; use super::simplify::{remove_dead_blocks, CfgSimplifier}; use crate::transform::{MirPass, MirSource}; use std::collections::VecDeque; use std::iter; -use rustc_attr as attr; -use rustc_target::spec::abi::Abi; - const DEFAULT_THRESHOLD: usize = 50; const HINT_THRESHOLD: usize = 100; diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 5942ef3a4c9..569737545f0 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -1,16 +1,15 @@ use crate::{shim, util}; -use rustc::hir::map::Map; use rustc::mir::{BodyAndCache, ConstQualifs, MirPhase, Promoted}; use rustc::ty::query::Providers; use rustc::ty::steal::Steal; use rustc::ty::{InstanceDef, TyCtxt, TypeFoldable}; +use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_index::vec::IndexVec; use rustc_span::Span; use std::borrow::Cow; -use syntax::ast; pub mod add_call_guards; pub mod add_moves_for_packed_drops; @@ -87,8 +86,8 @@ fn mir_keys(tcx: TyCtxt<'_>, krate: CrateNum) -> &DefIdSet { } intravisit::walk_struct_def(self, v) } - type Map = Map<'tcx>; - fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, Self::Map> { + type Map = intravisit::ErasedMap<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } } @@ -123,7 +122,7 @@ impl<'tcx> MirSource<'tcx> { /// type `T`. pub fn default_name() -> Cow<'static, str> { let name = ::std::any::type_name::(); - if let Some(tail) = name.rfind(":") { Cow::from(&name[tail + 1..]) } else { Cow::from(name) } + if let Some(tail) = name.rfind(':') { Cow::from(&name[tail + 1..]) } else { Cow::from(name) } } /// A streamlined trait that you can implement to create a pass; the @@ -210,7 +209,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs { // We return the qualifs in the return place for every MIR body, even though it is only used // when deciding to promote a reference to a `const` for now. - validator.qualifs_in_return_place().into() + validator.qualifs_in_return_place() } fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index a5d59860c3d..1336206e186 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -18,10 +18,10 @@ use rustc::mir::*; use rustc::ty::cast::CastTy; use rustc::ty::subst::InternalSubsts; use rustc::ty::{self, List, TyCtxt, TypeFoldable}; +use rustc_ast::ast::LitKind; use rustc_hir::def_id::DefId; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; -use syntax::ast::LitKind; use rustc_index::vec::{Idx, IndexVec}; use rustc_target::spec::abi::Abi; @@ -407,15 +407,17 @@ impl<'tcx> Validator<'_, 'tcx> { // FIXME(eddyb) maybe cache this? fn qualif_local(&self, local: Local) -> bool { - let per_local = &mut |l| self.qualif_local::(l); - if let TempState::Defined { location: loc, .. } = self.temps[local] { let num_stmts = self.body[loc.block].statements.len(); if loc.statement_index < num_stmts { let statement = &self.body[loc.block].statements[loc.statement_index]; match &statement.kind { - StatementKind::Assign(box (_, rhs)) => Q::in_rvalue(&self.item, per_local, rhs), + StatementKind::Assign(box (_, rhs)) => qualifs::in_rvalue::( + &self.item, + &mut |l| self.qualif_local::(l), + rhs, + ), _ => { span_bug!( statement.source_info.span, @@ -427,9 +429,9 @@ impl<'tcx> Validator<'_, 'tcx> { } else { let terminator = self.body[loc.block].terminator(); match &terminator.kind { - TerminatorKind::Call { func, args, .. } => { + TerminatorKind::Call { .. } => { let return_ty = self.body.local_decls[local].ty; - Q::in_call(&self.item, per_local, func, args, return_ty) + Q::in_any_value_of_ty(&self.item, return_ty) } kind => { span_bug!(terminator.source_info.span, "{:?} not promotable", kind); @@ -474,7 +476,7 @@ impl<'tcx> Validator<'_, 'tcx> { } } - fn validate_place(&self, place: PlaceRef<'_, 'tcx>) -> Result<(), Unpromotable> { + fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> { match place { PlaceRef { local, projection: [] } => self.validate_local(local), PlaceRef { local: _, projection: [proj_base @ .., elem] } => { @@ -920,7 +922,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut(); match candidate { Candidate::Ref(loc) => { - let ref mut statement = blocks[loc.block].statements[loc.statement_index]; + let statement = &mut blocks[loc.block].statements[loc.statement_index]; match statement.kind { StatementKind::Assign(box ( _, @@ -971,7 +973,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { } } Candidate::Repeat(loc) => { - let ref mut statement = blocks[loc.block].statements[loc.statement_index]; + let statement = &mut blocks[loc.block].statements[loc.statement_index]; match statement.kind { StatementKind::Assign(box (_, Rvalue::Repeat(ref mut operand, _))) => { let ty = operand.ty(local_decls, self.tcx); diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index b12f4ce3269..5a99ee27301 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -10,6 +10,14 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -> McfResult { + // Prevent const trait methods from being annotated as `stable`. + if tcx.features().staged_api { + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) { + return Err((body.span, "trait methods cannot be stable const fn".into())); + } + } + let mut current = def_id; loop { let predicates = tcx.predicates_of(current); diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 7d8506eb281..22ac3410a75 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -1,7 +1,7 @@ +use rustc_ast::ast; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi::Abi; -use syntax::ast; use crate::transform::{MirPass, MirSource}; use rustc::mir::{self, Body, BodyAndCache, Local, Location}; @@ -12,9 +12,8 @@ use rustc_index::bit_set::BitSet; use crate::dataflow::generic::{Analysis, Results, ResultsCursor}; use crate::dataflow::move_paths::{HasMoveData, MoveData}; use crate::dataflow::move_paths::{LookupResult, MovePathIndex}; -use crate::dataflow::IndirectlyMutableLocals; +use crate::dataflow::MaybeMutBorrowedLocals; use crate::dataflow::MoveDataParamEnv; -use crate::dataflow::{do_dataflow, DebugFormatted}; use crate::dataflow::{ DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, }; @@ -24,7 +23,6 @@ pub struct SanityCheck; impl<'tcx> MirPass<'tcx> for SanityCheck { fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) { use crate::dataflow::has_rustc_mir_with; - let def_id = src.def_id(); if !tcx.has_attr(def_id, sym::rustc_mir) { debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); @@ -36,8 +34,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck { let attributes = tcx.get_attrs(def_id); let param_env = tcx.param_env(def_id); let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap(); - let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; - let dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); + let mdpe = MoveDataParamEnv { move_data, param_env }; let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe) .into_engine(tcx, body, def_id) @@ -48,15 +45,9 @@ impl<'tcx> MirPass<'tcx> for SanityCheck { let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe) .into_engine(tcx, body, def_id) .iterate_to_fixpoint(); - let _flow_indirectly_mut = do_dataflow( - tcx, - body, - def_id, - &attributes, - &dead_unwinds, - IndirectlyMutableLocals::new(tcx, body, param_env), - |_, i| DebugFormatted::new(&i), - ); + let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env) + .into_engine(tcx, body, def_id) + .iterate_to_fixpoint(); if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_init).is_some() { sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_inits); @@ -67,12 +58,9 @@ impl<'tcx> MirPass<'tcx> for SanityCheck { if has_rustc_mir_with(&attributes, sym::rustc_peek_definite_init).is_some() { sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_def_inits); } - // FIXME: Uncomment these as analyses are migrated to the new framework - /* if has_rustc_mir_with(&attributes, sym::rustc_peek_indirectly_mutable).is_some() { - sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_indirectly_mut); + sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_mut_borrowed); } - */ if has_rustc_mir_with(&attributes, sym::stop_after_dataflow).is_some() { tcx.sess.fatal("stop_after_dataflow ended compilation"); } @@ -276,8 +264,7 @@ where } } -/* FIXME: Add this back once `IndirectlyMutableLocals` uses the new dataflow framework. -impl<'tcx> RustcPeekAt<'tcx> for IndirectlyMutableLocals<'_, 'tcx> { +impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> { fn peek_at( &self, tcx: TyCtxt<'tcx>, @@ -298,4 +285,3 @@ impl<'tcx> RustcPeekAt<'tcx> for IndirectlyMutableLocals<'_, 'tcx> { } } } -*/ diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index ddf8d73e548..4c54a46642f 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -95,6 +95,11 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { let mut start = START_BLOCK; + // Vec of the blocks that should be merged. We store the indices here, instead of the + // statements itself to avoid moving the (relatively) large statements twice. + // We do not push the statements directly into the target block (`bb`) as that is slower + // due to additional reallocations + let mut merged_blocks = Vec::new(); loop { let mut changed = false; @@ -114,18 +119,28 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { self.collapse_goto_chain(successor, &mut changed); } - let mut new_stmts = vec![]; let mut inner_changed = true; + merged_blocks.clear(); while inner_changed { inner_changed = false; inner_changed |= self.simplify_branch(&mut terminator); - inner_changed |= self.merge_successor(&mut new_stmts, &mut terminator); + inner_changed |= self.merge_successor(&mut merged_blocks, &mut terminator); changed |= inner_changed; } - let data = &mut self.basic_blocks[bb]; - data.statements.extend(new_stmts); - data.terminator = Some(terminator); + let statements_to_merge = + merged_blocks.iter().map(|&i| self.basic_blocks[i].statements.len()).sum(); + + if statements_to_merge > 0 { + let mut statements = std::mem::take(&mut self.basic_blocks[bb].statements); + statements.reserve(statements_to_merge); + for &from in &merged_blocks { + statements.append(&mut self.basic_blocks[from].statements); + } + self.basic_blocks[bb].statements = statements; + } + + self.basic_blocks[bb].terminator = Some(terminator); changed |= inner_changed; } @@ -199,7 +214,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { // merge a block with 1 `goto` predecessor to its parent fn merge_successor( &mut self, - new_stmts: &mut Vec>, + merged_blocks: &mut Vec, terminator: &mut Terminator<'tcx>, ) -> bool { let target = match terminator.kind { @@ -216,7 +231,8 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { return false; } }; - new_stmts.extend(self.basic_blocks[target].statements.drain(..)); + + merged_blocks.push(target); self.pred_count[target] = 0; true @@ -230,7 +246,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { }; let first_succ = { - if let Some(&first_succ) = terminator.successors().nth(0) { + if let Some(&first_succ) = terminator.successors().next() { if terminator.successors().all(|s| *s == first_succ) { let count = terminator.successors().count(); self.pred_count[first_succ] -= (count - 1) as u32; diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs index bd661195a48..3f28f033047 100644 --- a/src/librustc_mir/transform/simplify_try.rs +++ b/src/librustc_mir/transform/simplify_try.rs @@ -52,6 +52,8 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { Some(x) => x, }; if local_tmp_s0 != local_tmp_s1 + // Avoid moving into ourselves. + || local_0 == local_1 // The field-and-variant information match up. || vf_s0 != vf_s1 // Source and target locals have the same type. @@ -64,6 +66,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { } // Right shape; transform! + s0.source_info = s2.source_info; match &mut s0.kind { StatementKind::Assign(box (place, rvalue)) => { *place = local_0.into(); diff --git a/src/librustc_mir/transform/uninhabited_enum_branching.rs b/src/librustc_mir/transform/uninhabited_enum_branching.rs index 0bf0ff2852d..bbaa66f5954 100644 --- a/src/librustc_mir/transform/uninhabited_enum_branching.rs +++ b/src/librustc_mir/transform/uninhabited_enum_branching.rs @@ -28,7 +28,7 @@ fn get_switched_on_type<'tcx>( // Only bother checking blocks which terminate by switching on a local. if let Some(local) = get_discriminant_local(&terminator.kind) { - let stmt_before_term = (block_data.statements.len() > 0) + let stmt_before_term = (!block_data.statements.is_empty()) .then(|| &block_data.statements[block_data.statements.len() - 1].kind); if let Some(StatementKind::Assign(box (l, Rvalue::Discriminant(place)))) = stmt_before_term @@ -100,7 +100,7 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { &mut body.basic_blocks_mut()[bb].terminator_mut().kind { let vals = &*values; - let zipped = vals.iter().zip(targets.into_iter()); + let zipped = vals.iter().zip(targets.iter()); let mut matched_values = Vec::with_capacity(allowed_variants.len()); let mut matched_targets = Vec::with_capacity(allowed_variants.len() + 1); diff --git a/src/librustc_mir/util/aggregate.rs b/src/librustc_mir/util/aggregate.rs index be515ef5713..927c8f6dfb2 100644 --- a/src/librustc_mir/util/aggregate.rs +++ b/src/librustc_mir/util/aggregate.rs @@ -49,7 +49,6 @@ pub fn expand_aggregate<'tcx>( }; operands - .into_iter() .enumerate() .map(move |(i, (op, ty))| { let lhs_field = if let AggregateKind::Array(_) = kind { diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 091ae1bbb79..ecf0a8ea83c 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -153,9 +153,9 @@ where // FIXME: I think we should just control the flags externally, // and then we do not need this machinery. pub fn elaborate_drop(&mut self, bb: BasicBlock) { - debug!("elaborate_drop({:?})", self); + debug!("elaborate_drop({:?}, {:?})", bb, self); let style = self.elaborator.drop_style(self.path, DropFlagMode::Deep); - debug!("elaborate_drop({:?}): live - {:?}", self, style); + debug!("elaborate_drop({:?}, {:?}): live - {:?}", bb, self, style); match style { DropStyle::Dead => { self.elaborator @@ -369,7 +369,7 @@ where fn open_drop_for_adt(&mut self, adt: &'tcx ty::AdtDef, substs: SubstsRef<'tcx>) -> BasicBlock { debug!("open_drop_for_adt({:?}, {:?}, {:?})", self, adt, substs); - if adt.variants.len() == 0 { + if adt.variants.is_empty() { return self.elaborator.patch().new_block(BasicBlockData { statements: vec![], terminator: Some(Terminator { @@ -426,25 +426,21 @@ where let mut unwind_blocks = if unwind.is_cleanup() { None } else { Some(Vec::with_capacity(adt.variants.len())) }; + let mut have_otherwise_with_drop_glue = false; let mut have_otherwise = false; let tcx = self.tcx(); for (variant_index, discr) in adt.discriminants(tcx) { + let variant = &adt.variants[variant_index]; let subpath = self.elaborator.downcast_subpath(self.path, variant_index); + if let Some(variant_path) = subpath { let base_place = tcx.mk_place_elem( self.place.clone(), - ProjectionElem::Downcast( - Some(adt.variants[variant_index].ident.name), - variant_index, - ), - ); - let fields = self.move_paths_for_fields( - &base_place, - variant_path, - &adt.variants[variant_index], - substs, + ProjectionElem::Downcast(Some(variant.ident.name), variant_index), ); + let fields = + self.move_paths_for_fields(&base_place, variant_path, &variant, substs); values.push(discr.val); if let Unwind::To(unwind) = unwind { // We can't use the half-ladder from the original @@ -474,16 +470,30 @@ where normal_blocks.push(normal); } else { have_otherwise = true; + + let param_env = self.elaborator.param_env(); + let have_field_with_drop_glue = variant + .fields + .iter() + .any(|field| field.ty(tcx, substs).needs_drop(tcx, param_env)); + if have_field_with_drop_glue { + have_otherwise_with_drop_glue = true; + } } } - if have_otherwise { + if !have_otherwise { + values.pop(); + } else if !have_otherwise_with_drop_glue { + normal_blocks.push(self.goto_block(succ, unwind)); + if let Unwind::To(unwind) = unwind { + unwind_blocks.as_mut().unwrap().push(self.goto_block(unwind, Unwind::InCleanup)); + } + } else { normal_blocks.push(self.drop_block(succ, unwind)); if let Unwind::To(unwind) = unwind { unwind_blocks.as_mut().unwrap().push(self.drop_block(unwind, Unwind::InCleanup)); } - } else { - values.pop(); } ( @@ -539,7 +549,7 @@ where debug!("destructor_call_block({:?}, {:?})", self, succ); let tcx = self.tcx(); let drop_trait = tcx.lang_items().drop_trait().unwrap(); - let drop_fn = tcx.associated_items(drop_trait)[0]; + let drop_fn = tcx.associated_items(drop_trait).in_definition_order().next().unwrap(); let ty = self.place_ty(self.place); let substs = tcx.mk_substs_trait(ty, &[]); @@ -721,7 +731,7 @@ where self.elaborator.patch().new_block(base_block) } - /// Ceates a pair of drop-loops of `place`, which drops its contents, even + /// Creates a pair of drop-loops of `place`, which drops its contents, even /// in the case of 1 panic. If `ptr_based`, creates a pointer loop, /// otherwise create an index loop. fn drop_loop_pair( @@ -862,7 +872,7 @@ where debug!("drop_flag_reset_block({:?},{:?})", self, mode); let block = self.new_block(unwind, TerminatorKind::Goto { target: succ }); - let block_start = Location { block: block, statement_index: 0 }; + let block_start = Location { block, statement_index: 0 }; self.elaborator.clear_drop_flag(block_start, self.path, mode); block } @@ -911,7 +921,7 @@ where let call = TerminatorKind::Call { func: Operand::function_handle(tcx, free_func, substs, self.source_info.span), - args: args, + args, destination: Some((unit_temp, target)), cleanup: None, from_hir_call: false, @@ -929,6 +939,11 @@ where self.new_block(unwind, block) } + fn goto_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { + let block = TerminatorKind::Goto { target }; + self.new_block(unwind, block) + } + fn drop_flag_test_block( &mut self, on_set: BasicBlock, diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index b12ad1e4c15..f6c6f555495 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -293,7 +293,7 @@ fn dump_matched_mir_node<'tcx>( writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?; writeln!(file, "// source = {:?}", source)?; writeln!(file, "// pass_name = {}", pass_name)?; - writeln!(file, "")?; + writeln!(file)?; write_mir_fn(tcx, source, body, &mut file, result)?; Ok(()) }); @@ -316,7 +316,7 @@ pub fn write_mir_fn<'tcx>( write_basic_block(tcx, block, body, &mut |_, _| Ok(()), w)?; print(w, " ", &result.outs)?; if block.index() + 1 != body.basic_blocks().len() { - writeln!(w, "")?; + writeln!(w)?; } } diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index 68aa82f902f..473692a43f3 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -37,7 +37,7 @@ impl<'tcx> MirPatch<'tcx> { let mut resume_stmt_block = None; for (bb, block) in body.basic_blocks().iter_enumerated() { if let TerminatorKind::Resume = block.terminator().kind { - if block.statements.len() > 0 { + if !block.statements.is_empty() { assert!(resume_stmt_block.is_none()); resume_stmt_block = Some(bb); } else { diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index e0919e7e8f8..f8dfddef2bb 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -134,7 +134,7 @@ fn dump_matched_mir_node<'tcx, F>( if let Some(ref layout) = body.generator_layout { writeln!(file, "// generator_layout = {:?}", layout)?; } - writeln!(file, "")?; + writeln!(file)?; extra_data(PassWhere::BeforeCFG, &mut file)?; write_user_type_annotations(body, &mut file)?; write_mir_fn(tcx, source, body, &mut extra_data, &mut file)?; @@ -242,13 +242,13 @@ pub fn write_mir_pretty<'tcx>( first = false; } else { // Put empty lines between all items - writeln!(w, "")?; + writeln!(w)?; } write_mir_fn(tcx, MirSource::item(def_id), body, &mut |_, _| Ok(()), w)?; for (i, body) in tcx.promoted_mir(def_id).iter_enumerated() { - writeln!(w, "")?; + writeln!(w)?; let src = MirSource { instance: ty::InstanceDef::Item(def_id), promoted: Some(i) }; write_mir_fn(tcx, src, body, &mut |_, _| Ok(()), w)?; } @@ -271,7 +271,7 @@ where extra_data(PassWhere::BeforeBlock(block), w)?; write_basic_block(tcx, block, body, extra_data, w)?; if block.index() + 1 != body.basic_blocks().len() { - writeln!(w, "")?; + writeln!(w)?; } } @@ -297,7 +297,7 @@ where writeln!(w, "{}{:?}{}: {{", INDENT, block, cleanup_text)?; // List of statements in the middle. - let mut current_location = Location { block: block, statement_index: 0 }; + let mut current_location = Location { block, statement_index: 0 }; for statement in &data.statements { extra_data(PassWhere::BeforeLocation(current_location), w)?; let indented_body = format!("{0}{0}{1:?};", INDENT, statement); @@ -477,7 +477,7 @@ fn write_scope_tree( indented_decl.push_str(";"); let local_name = - if local == RETURN_PLACE { format!(" return place") } else { String::new() }; + if local == RETURN_PLACE { " return place".to_string() } else { String::new() }; writeln!( w, @@ -490,7 +490,7 @@ fn write_scope_tree( } let children = match scope_tree.get(&parent) { - Some(childs) => childs, + Some(children) => children, None => return Ok(()), }; @@ -529,7 +529,7 @@ pub fn write_mir_intro<'tcx>( write_scope_tree(tcx, body, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1)?; // Add an empty line before the first block is printed. - writeln!(w, "")?; + writeln!(w)?; Ok(()) } @@ -545,7 +545,7 @@ fn write_mir_sig( trace!("write_mir_sig: {:?}", src.instance); let kind = tcx.def_kind(src.def_id()); let is_function = match kind { - Some(DefKind::Fn) | Some(DefKind::Method) | Some(DefKind::Ctor(..)) => true, + Some(DefKind::Fn) | Some(DefKind::AssocFn) | Some(DefKind::Ctor(..)) => true, _ => tcx.is_closure(src.def_id()), }; match (kind, src.promoted) { diff --git a/src/librustc_mir_build/Cargo.toml b/src/librustc_mir_build/Cargo.toml index c109e9c618e..96716dbd604 100644 --- a/src/librustc_mir_build/Cargo.toml +++ b/src/librustc_mir_build/Cargo.toml @@ -19,10 +19,12 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_index = { path = "../librustc_index" } rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } +rustc_infer = { path = "../librustc_infer" } rustc_macros = { path = "../librustc_macros" } rustc_serialize = { path = "../libserialize", package = "serialize" } rustc_session = { path = "../librustc_session" } rustc_span = { path = "../librustc_span" } rustc_target = { path = "../librustc_target" } -syntax = { path = "../libsyntax" } +rustc_trait_selection = { path = "../librustc_trait_selection" } +rustc_ast = { path = "../librustc_ast" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_mir_build/build/expr/as_place.rs b/src/librustc_mir_build/build/expr/as_place.rs index 907300d45aa..d77cc49c94f 100644 --- a/src/librustc_mir_build/build/expr/as_place.rs +++ b/src/librustc_mir_build/build/expr/as_place.rs @@ -5,7 +5,7 @@ use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; use rustc::middle::region; -use rustc::mir::interpret::PanicInfo::BoundsCheck; +use rustc::mir::AssertKind::BoundsCheck; use rustc::mir::*; use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}; use rustc_span::Span; diff --git a/src/librustc_mir_build/build/expr/as_rvalue.rs b/src/librustc_mir_build/build/expr/as_rvalue.rs index 6f5c5f0dd4c..dc97f321a36 100644 --- a/src/librustc_mir_build/build/expr/as_rvalue.rs +++ b/src/librustc_mir_build/build/expr/as_rvalue.rs @@ -6,7 +6,7 @@ use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; use rustc::middle::region; -use rustc::mir::interpret::PanicInfo; +use rustc::mir::AssertKind; use rustc::mir::*; use rustc::ty::{self, Ty, UpvarSubsts}; use rustc_span::Span; @@ -86,7 +86,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Operand::Move(is_min), false, - PanicInfo::OverflowNeg, + AssertKind::OverflowNeg, expr_span, ); } @@ -294,7 +294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let val = tcx.mk_place_field(result_value.clone(), val_fld, ty); let of = tcx.mk_place_field(result_value, of_fld, bool_ty); - let err = PanicInfo::Overflow(op); + let err = AssertKind::Overflow(op); block = self.assert(block, Operand::Move(of), false, err, span); @@ -305,11 +305,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // and 2. there are two possible failure cases, divide-by-zero and overflow. let zero_err = if op == BinOp::Div { - PanicInfo::DivisionByZero + AssertKind::DivisionByZero } else { - PanicInfo::RemainderByZero + AssertKind::RemainderByZero }; - let overflow_err = PanicInfo::Overflow(op); + let overflow_err = AssertKind::Overflow(op); // Check for / 0 let is_zero = self.temp(bool_ty, span); diff --git a/src/librustc_mir_build/build/expr/into.rs b/src/librustc_mir_build/build/expr/into.rs index 51b0b5bc7cb..4583e244f49 100644 --- a/src/librustc_mir_build/build/expr/into.rs +++ b/src/librustc_mir_build/build/expr/into.rs @@ -376,7 +376,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TerminatorKind::Yield { value, resume, - resume_arg: destination.clone(), + resume_arg: *destination, drop: cleanup, }, ); diff --git a/src/librustc_mir_build/build/matches/mod.rs b/src/librustc_mir_build/build/matches/mod.rs index f900ae45b94..e7c7e2b47f2 100644 --- a/src/librustc_mir_build/build/matches/mod.rs +++ b/src/librustc_mir_build/build/matches/mod.rs @@ -19,7 +19,7 @@ use rustc_hir::HirId; use rustc_index::bit_set::BitSet; use rustc_span::Span; use smallvec::{smallvec, SmallVec}; -use syntax::ast::Name; +use rustc_ast::ast::Name; // helper functions, broken out by category: mod simplify; @@ -649,7 +649,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } PatKind::Or { ref pats } => { - self.visit_bindings(&pats[0], pattern_user_ty.clone(), f); + self.visit_bindings(&pats[0], pattern_user_ty, f); } } } @@ -1438,7 +1438,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target_blocks: Vec<_> = target_candidates .into_iter() .map(|mut candidates| { - if candidates.len() != 0 { + if !candidates.is_empty() { let candidate_start = this.cfg.start_new_block(); this.match_candidates( span, @@ -1942,8 +1942,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.hir.tcx(); let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope }; let binding_mode = match mode { - BindingMode::ByValue => ty::BindingMode::BindByValue(mutability.into()), - BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability.into()), + BindingMode::ByValue => ty::BindingMode::BindByValue(mutability), + BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability), }; debug!("declare_binding: user_ty={:?}", user_ty); let local = LocalDecl::<'tcx> { diff --git a/src/librustc_mir_build/build/matches/simplify.rs b/src/librustc_mir_build/build/matches/simplify.rs index 56aa150dd37..aea4f5f1b3a 100644 --- a/src/librustc_mir_build/build/matches/simplify.rs +++ b/src/librustc_mir_build/build/matches/simplify.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // value being matched, taking the variance field into account. candidate.ascriptions.push(Ascription { span: user_ty_span, - user_ty: user_ty, + user_ty, source: match_pair.place, variance, }); @@ -209,7 +209,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { i == variant_index || { self.hir.tcx().features().exhaustive_patterns && !v - .uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind()) + .uninhabited_from( + self.hir.tcx(), + substs, + adt_def.adt_kind(), + self.hir.param_env, + ) .is_empty() } }) && (adt_def.did.is_local() diff --git a/src/librustc_mir_build/build/matches/test.rs b/src/librustc_mir_build/build/matches/test.rs index 1acfa7dddbe..d23a2708dc4 100644 --- a/src/librustc_mir_build/build/matches/test.rs +++ b/src/librustc_mir_build/build/matches/test.rs @@ -64,10 +64,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Slice { ref prefix, ref slice, ref suffix } => { let len = prefix.len() + suffix.len(); let op = if slice.is_some() { BinOp::Ge } else { BinOp::Eq }; - Test { - span: match_pair.pattern.span, - kind: TestKind::Len { len: len as u64, op: op }, - } + Test { span: match_pair.pattern.span, kind: TestKind::Len { len: len as u64, op } } } PatKind::Or { .. } => bug!("or-patterns should have already been handled"), @@ -222,7 +219,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::SwitchInt { switch_ty, ref options, indices: _ } => { let target_blocks = make_target_blocks(self); let terminator = if switch_ty.kind == ty::Bool { - assert!(options.len() > 0 && options.len() <= 2); + assert!(!options.is_empty() && options.len() <= 2); if let [first_bb, second_bb] = *target_blocks { let (true_bb, false_bb) = match options[0] { 1 => (first_bb, second_bb), diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index 32b1f2b6e13..821c4d68c7e 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -12,6 +12,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{GeneratorKind, HirIdMap, Node}; use rustc_index::vec::{Idx, IndexVec}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_span::symbol::kw; use rustc_span::Span; use rustc_target::spec::abi::Abi; @@ -38,12 +39,12 @@ fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> BodyAndCache<'_> { .. }) | Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Method(hir::FnSig { decl, .. }, body_id), + kind: hir::ImplItemKind::Fn(hir::FnSig { decl, .. }, body_id), .. }) | Node::TraitItem(hir::TraitItem { kind: - hir::TraitItemKind::Method(hir::FnSig { decl, .. }, hir::TraitMethod::Provided(body_id)), + hir::TraitItemKind::Fn(hir::FnSig { decl, .. }, hir::TraitFn::Provided(body_id)), .. }) => (*body_id, decl.output.span()), Node::Item(hir::Item { kind: hir::ItemKind::Static(ty, _, body_id), .. }) @@ -417,7 +418,7 @@ struct GuardFrameLocal { impl GuardFrameLocal { fn new(id: hir::HirId, _binding_mode: BindingMode) -> Self { - GuardFrameLocal { id: id } + GuardFrameLocal { id } } } @@ -670,14 +671,51 @@ fn construct_const<'a, 'tcx>( builder.finish() } +/// Construct MIR for a item that has had errors in type checking. +/// +/// This is required because we may still want to run MIR passes on an item +/// with type errors, but normal MIR construction can't handle that in general. fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'tcx> { - let owner_id = hir.tcx().hir().body_owner(body_id); - let span = hir.tcx().hir().span(owner_id); - let ty = hir.tcx().types.err; - let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, None); + let tcx = hir.tcx(); + let owner_id = tcx.hir().body_owner(body_id); + let span = tcx.hir().span(owner_id); + let ty = tcx.types.err; + let num_params = match hir.body_owner_kind { + hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len(), + hir::BodyOwnerKind::Closure => { + if tcx.hir().body(body_id).generator_kind().is_some() { + // Generators have an implicit `self` parameter *and* a possibly + // implicit resume parameter. + 2 + } else { + // The implicit self parameter adds another local in MIR. + 1 + tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len() + } + } + hir::BodyOwnerKind::Const => 0, + hir::BodyOwnerKind::Static(_) => 0, + }; + let mut builder = Builder::new(hir, span, num_params, Safety::Safe, ty, span, None); let source_info = builder.source_info(span); + // Some MIR passes will expect the number of parameters to match the + // function declaration. + for _ in 0..num_params { + builder.local_decls.push(LocalDecl { + mutability: Mutability::Mut, + ty, + user_ty: UserTypeProjections::none(), + source_info, + internal: false, + local_info: LocalInfo::Other, + is_block_tail: None, + }); + } builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); - builder.finish() + let mut body = builder.finish(); + if tcx.hir().body(body_id).generator_kind.is_some() { + body.yield_ty = Some(ty); + } + body } impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -844,7 +882,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span: tcx_hir.span(var_id), }, place: Place { - local: closure_env_arg.into(), + local: closure_env_arg, projection: tcx.intern_place_elems(&projs), }, }); @@ -889,7 +927,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.local_decls[local].local_info = if let Some(kind) = self_binding { LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind))) } else { - let binding_mode = ty::BindingMode::BindByValue(mutability.into()); + let binding_mode = ty::BindingMode::BindByValue(mutability); LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( VarBindingForm { binding_mode, diff --git a/src/librustc_mir_build/hair/constant.rs b/src/librustc_mir_build/hair/constant.rs index 266f4738c50..d5e5398b9d4 100644 --- a/src/librustc_mir_build/hair/constant.rs +++ b/src/librustc_mir_build/hair/constant.rs @@ -1,9 +1,9 @@ use rustc::mir::interpret::{ truncate, Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, }; -use rustc::ty::{self, layout::Size, ParamEnv, TyCtxt}; +use rustc::ty::{self, layout::Size, ParamEnv, TyCtxt, TyS}; +use rustc_ast::ast; use rustc_span::symbol::Symbol; -use syntax::ast; crate fn lit_to_const<'tcx>( tcx: TyCtxt<'tcx>, @@ -20,52 +20,37 @@ crate fn lit_to_const<'tcx>( Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) }; - let lit = match *lit { - ast::LitKind::Str(ref s, _) => { + let lit = match (lit, &ty.kind) { + (ast::LitKind::Str(s, _), ty::Ref(_, TyS { kind: ty::Str, .. }, _)) => { let s = s.as_str(); let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes()); let allocation = tcx.intern_const_alloc(allocation); ConstValue::Slice { data: allocation, start: 0, end: s.len() } } - ast::LitKind::ByteStr(ref data) => { - if let ty::Ref(_, ref_ty, _) = ty.kind { - match ref_ty.kind { - ty::Slice(_) => { - let allocation = Allocation::from_byte_aligned_bytes(data as &Vec); - let allocation = tcx.intern_const_alloc(allocation); - ConstValue::Slice { data: allocation, start: 0, end: data.len() } - } - ty::Array(_, _) => { - let id = tcx.allocate_bytes(data); - ConstValue::Scalar(Scalar::Ptr(id.into())) - } - _ => { - bug!("bytestring should have type of either &[u8] or &[u8; _], not {}", ty) - } - } - } else { - bug!("bytestring should have type of either &[u8] or &[u8; _], not {}", ty) - } + (ast::LitKind::ByteStr(data), ty::Ref(_, TyS { kind: ty::Slice(_), .. }, _)) => { + let allocation = Allocation::from_byte_aligned_bytes(data as &Vec); + let allocation = tcx.intern_const_alloc(allocation); + ConstValue::Slice { data: allocation, start: 0, end: data.len() } + } + (ast::LitKind::ByteStr(data), ty::Ref(_, TyS { kind: ty::Array(_, _), .. }, _)) => { + let id = tcx.allocate_bytes(data); + ConstValue::Scalar(Scalar::Ptr(id.into())) + } + (ast::LitKind::Byte(n), ty::Uint(ast::UintTy::U8)) => { + ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) } - ast::LitKind::Byte(n) => ConstValue::Scalar(Scalar::from_uint(n, Size::from_bytes(1))), - ast::LitKind::Int(n, _) if neg => { - let n = n as i128; - let n = n.overflowing_neg().0; - trunc(n as u128)? + (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => { + trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })? } - ast::LitKind::Int(n, _) => trunc(n)?, - ast::LitKind::Float(n, _) => { - let fty = match ty.kind { - ty::Float(fty) => fty, - _ => bug!(), - }; - parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)? + (ast::LitKind::Float(n, _), ty::Float(fty)) => { + parse_float(*n, *fty, neg).map_err(|_| LitToConstError::UnparseableFloat)? } - ast::LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)), - ast::LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)), - ast::LitKind::Err(_) => return Err(LitToConstError::Reported), + (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), + (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), + (ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported), + _ => return Err(LitToConstError::TypeError), }; - Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Value(lit), ty })) + Ok(ty::Const::from_value(tcx, lit, ty)) } fn parse_float<'tcx>(num: Symbol, fty: ast::FloatTy, neg: bool) -> Result, ()> { diff --git a/src/librustc_mir_build/hair/cx/block.rs b/src/librustc_mir_build/hair/cx/block.rs index a883b84f8fe..8d7225c8c7b 100644 --- a/src/librustc_mir_build/hair/cx/block.rs +++ b/src/librustc_mir_build/hair/cx/block.rs @@ -84,7 +84,7 @@ fn mirror_stmts<'a, 'tcx>( result.push(StmtRef::Mirror(Box::new(Stmt { kind: StmtKind::Let { - remainder_scope: remainder_scope, + remainder_scope, init_scope: region::Scope { id: hir_id.local_id, data: region::ScopeData::Node, diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index d6786ea2479..02b596863ab 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -10,7 +10,6 @@ use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::ty::{self, AdtKind, Ty}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; -use rustc_hir::def_id::LocalDefId; use rustc_index::vec::Idx; use rustc_span::Span; @@ -187,13 +186,12 @@ fn make_mirror_unadjusted<'a, 'tcx>( if let Some((adt_def, index)) = adt_data { let substs = cx.tables().node_substs(fun.hir_id); let user_provided_types = cx.tables().user_provided_types(); - let user_ty = - user_provided_types.get(fun.hir_id).map(|u_ty| *u_ty).map(|mut u_ty| { - if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value { - *did = adt_def.did; - } - u_ty - }); + let user_ty = user_provided_types.get(fun.hir_id).copied().map(|mut u_ty| { + if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value { + *did = adt_def.did; + } + u_ty + }); debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty); let field_refs = args @@ -329,7 +327,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( ty::Adt(adt, substs) => match adt.adt_kind() { AdtKind::Struct | AdtKind::Union => { let user_provided_types = cx.tables().user_provided_types(); - let user_ty = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty); + let user_ty = user_provided_types.get(expr.hir_id).copied(); debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty); ExprKind::Adt { adt_def: adt, @@ -351,7 +349,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( let index = adt.variant_index_with_id(variant_id); let user_provided_types = cx.tables().user_provided_types(); - let user_ty = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty); + let user_ty = user_provided_types.get(expr.hir_id).copied(); debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty); ExprKind::Adt { adt_def: adt, @@ -418,7 +416,17 @@ fn make_mirror_unadjusted<'a, 'tcx>( None, Some(span), ) { - Ok(cv) => cv.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()), + Ok(cv) => { + if let Some(count) = cv.try_to_bits_for_ty( + cx.tcx, + ty::ParamEnv::reveal_all(), + cx.tcx.types.usize, + ) { + count as u64 + } else { + bug!("repeat count constant value can't be converted to usize"); + } + } Err(ErrorHandled::Reported) => 0, Err(ErrorHandled::TooGeneric) => { let span = cx.tcx.def_span(def_id); @@ -560,7 +568,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( } hir::ExprKind::Type(ref source, ref ty) => { let user_provided_types = cx.tables.user_provided_types(); - let user_ty = user_provided_types.get(ty.hir_id).map(|u_ty| *u_ty); + let user_ty = user_provided_types.get(ty.hir_id).copied(); debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty); if source.is_syntactic_place_expr() { ExprKind::PlaceTypeAscription { source: source.to_ref(), user_ty } @@ -591,11 +599,11 @@ fn user_substs_applied_to_res<'tcx>( // a tuple-struct or tuple-variant. This has the type of a // `Fn` but with the user-given substitutions. Res::Def(DefKind::Fn, _) - | Res::Def(DefKind::Method, _) + | Res::Def(DefKind::AssocFn, _) | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => { - cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty) + cx.tables().user_provided_types().get(hir_id).copied() } // A unit struct/variant which is used as a value (e.g., @@ -694,7 +702,7 @@ fn convert_path_expr<'a, 'tcx>( match res { // A regular function, constructor function or a constant. Res::Def(DefKind::Fn, _) - | Res::Def(DefKind::Method, _) + | Res::Def(DefKind::AssocFn, _) | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => { let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res); @@ -734,7 +742,7 @@ fn convert_path_expr<'a, 'tcx>( Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => { let user_provided_types = cx.tables.user_provided_types(); - let user_provided_type = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty); + let user_provided_type = user_provided_types.get(expr.hir_id).copied(); debug!("convert_path_expr: user_provided_type={:?}", user_provided_type); let ty = cx.tables().node_type(expr.hir_id); match ty.kind { @@ -803,7 +811,7 @@ fn convert_var<'tcx>( let closure_def_id = cx.body_owner; let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: LocalDefId::from_def_id(closure_def_id), + closure_expr_id: closure_def_id.expect_local(), }; let var_ty = cx.tables().node_type(var_hir_id); @@ -978,7 +986,7 @@ fn capture_upvar<'tcx>( ) -> ExprRef<'tcx> { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id).to_local(), + closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id).expect_local(), }; let upvar_capture = cx.tables().upvar_capture(upvar_id); let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); diff --git a/src/librustc_mir_build/hair/cx/mod.rs b/src/librustc_mir_build/hair/cx/mod.rs index 497c6610550..99caa6a0f95 100644 --- a/src/librustc_mir_build/hair/cx/mod.rs +++ b/src/librustc_mir_build/hair/cx/mod.rs @@ -5,20 +5,21 @@ use crate::hair::util::UserAnnotatedTyHelpers; use crate::hair::*; -use rustc::infer::InferCtxt; use rustc::middle::region; use rustc::mir::interpret::{LitToConstError, LitToConstInput}; use rustc::ty::layout::VariantIdx; use rustc::ty::subst::Subst; use rustc::ty::subst::{GenericArg, InternalSubsts}; use rustc::ty::{self, Ty, TyCtxt}; +use rustc_ast::ast; +use rustc_ast::attr; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::Node; use rustc_index::vec::Idx; +use rustc_infer::infer::InferCtxt; use rustc_span::symbol::{sym, Symbol}; -use syntax::ast; -use syntax::attr; +use rustc_trait_selection::infer::InferCtxtExt; #[derive(Clone)] crate struct Cx<'a, 'tcx> { @@ -148,6 +149,7 @@ impl<'a, 'tcx> Cx<'a, 'tcx> { // create a dummy value and continue compiling Const::from_bits(self.tcx, 0, self.param_env.and(ty)) } + Err(LitToConstError::TypeError) => bug!("const_eval_literal: had type error"), } } @@ -167,17 +169,19 @@ impl<'a, 'tcx> Cx<'a, 'tcx> { params: &[GenericArg<'tcx>], ) -> &'tcx ty::Const<'tcx> { let substs = self.tcx.mk_substs_trait(self_ty, params); - for item in self.tcx.associated_items(trait_def_id) { - // The unhygienic comparison here is acceptable because this is only - // used on known traits. - if item.kind == ty::AssocKind::Method && item.ident.name == method_name { - let method_ty = self.tcx.type_of(item.def_id); - let method_ty = method_ty.subst(self.tcx, substs); - return ty::Const::zero_sized(self.tcx, method_ty); - } - } - bug!("found no method `{}` in `{:?}`", method_name, trait_def_id); + // The unhygienic comparison here is acceptable because this is only + // used on known traits. + let item = self + .tcx + .associated_items(trait_def_id) + .filter_by_name_unhygienic(method_name) + .find(|item| item.kind == ty::AssocKind::Method) + .expect("trait method not found"); + + let method_ty = self.tcx.type_of(item.def_id); + let method_ty = method_ty.subst(self.tcx, substs); + ty::Const::zero_sized(self.tcx, method_ty) } crate fn all_fields(&mut self, adt_def: &ty::AdtDef, variant_index: VariantIdx) -> Vec { diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 7ed6c81eb63..82810f35675 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -235,17 +235,15 @@ use rustc_index::vec::Idx; use super::{compare_const_vals, PatternFoldable, PatternFolder}; use super::{FieldPat, Pat, PatKind, PatRange}; -use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx}; -use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef}; -use rustc_hir::def_id::DefId; -use rustc_hir::{HirId, RangeEnd}; - -use rustc::lint; use rustc::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar}; use rustc::mir::Field; +use rustc::ty::layout::{Integer, IntegerExt, Size, VariantIdx}; +use rustc::ty::{self, Const, Ty, TyCtxt, TypeFoldable, VariantDef}; use rustc::util::common::ErrorReported; - use rustc_attr::{SignedInt, UnsignedInt}; +use rustc_hir::def_id::DefId; +use rustc_hir::{HirId, RangeEnd}; +use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; use arena::TypedArena; @@ -343,12 +341,11 @@ impl<'tcx> PatternFolder<'tcx> for LiteralExpander<'tcx> { ty: rty, span: pat.span, kind: box PatKind::Constant { - value: self.tcx.mk_const(Const { - val: ty::ConstKind::Value( - self.fold_const_value_deref(*val, rty, crty), - ), - ty: rty, - }), + value: Const::from_value( + self.tcx, + self.fold_const_value_deref(*val, rty, crty), + rty, + ), }, }, }, @@ -412,7 +409,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { } fn iter(&self) -> impl Iterator> { - self.0.iter().map(|p| *p) + self.0.iter().copied() } // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`. @@ -481,7 +478,11 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it. crate fn push(&mut self, row: PatStack<'p, 'tcx>) { if let Some(rows) = row.expand_or_pat() { - self.0.extend(rows); + for row in rows { + // We recursively expand the or-patterns of the new rows. + // This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`. + self.push(row) + } } else { self.0.push(row); } @@ -595,7 +596,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { if self.tcx.features().exhaustive_patterns { - self.tcx.is_ty_uninhabited_from(self.module, ty) + self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env) } else { false } @@ -838,7 +839,7 @@ impl<'tcx> Constructor<'tcx> { // eliminate it straight away. remaining_ranges = vec![]; } else { - // Otherwise explicitely compute the remaining ranges. + // Otherwise explicitly compute the remaining ranges. remaining_ranges = other_range.subtract_from(remaining_ranges); } @@ -1001,7 +1002,7 @@ impl<'tcx> Constructor<'tcx> { PatKind::Leaf { subpatterns } } } - ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.nth(0).unwrap() }, + ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, ty), _ => PatKind::Wild, }, @@ -1264,7 +1265,7 @@ fn all_constructors<'a, 'tcx>( def.variants .iter() .filter(|v| { - !v.uninhabited_from(cx.tcx, substs, def.adt_kind()) + !v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env) .contains(cx.tcx, cx.module) }) .map(|v| Variant(v.def_id)) @@ -1397,21 +1398,19 @@ impl<'tcx> IntRange<'tcx> { ) -> Option> { if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) { let ty = value.ty; - let val = if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, size })) = - value.val - { - // For this specific pattern we can skip a lot of effort and go - // straight to the result, after doing a bit of checking. (We - // could remove this branch and just use the next branch, which - // is more general but much slower.) - Scalar::<()>::check_raw(data, size, target_size); - data - } else if let Some(val) = value.try_eval_bits(tcx, param_env, ty) { - // This is a more general form of the previous branch. - val - } else { - return None; - }; + let val = (|| { + if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val { + // For this specific pattern we can skip a lot of effort and go + // straight to the result, after doing a bit of checking. (We + // could remove this branch and just fall through, which + // is more general but much slower.) + if let Ok(bits) = scalar.to_bits_or_ptr(target_size, &tcx) { + return Some(bits); + } + } + // This is a more general form of the previous case. + value.try_eval_bits(tcx, param_env, ty) + })()?; let val = val ^ bias; Some(IntRange { range: val..=val, ty, span }) } else { @@ -2334,7 +2333,7 @@ fn specialize_one_pattern<'p, 'tcx>( PatKind::Binding { .. } | PatKind::Wild => Some(ctor_wild_subpatterns.iter().collect()), PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => { - let ref variant = adt_def.variants[variant_index]; + let variant = &adt_def.variants[variant_index]; let is_non_exhaustive = cx.is_foreign_non_exhaustive_variant(pat.ty, variant); Some(Variant(variant.def_id)) .filter(|variant_constructor| variant_constructor == constructor) diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs index 651f2f70d9b..9c86669cf9d 100644 --- a/src/librustc_mir_build/hair/pattern/check_match.rs +++ b/src/librustc_mir_build/hair/pattern/check_match.rs @@ -4,8 +4,8 @@ use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack} use super::{PatCtxt, PatKind, PatternError}; -use rustc::hir::map::Map; use rustc::ty::{self, Ty, TyCtxt}; +use rustc_ast::ast::Mutability; use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::*; @@ -17,7 +17,6 @@ use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERN use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::{sym, Span}; -use syntax::ast::Mutability; use std::slice; @@ -43,9 +42,9 @@ struct MatchVisitor<'a, 'tcx> { } impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { - type Map = Map<'tcx>; + type Map = intravisit::ErasedMap<'tcx>; - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } @@ -87,6 +86,9 @@ impl PatCtxt<'_, '_> { PatternError::AssocConstInPattern(span) => { self.span_e0158(span, "associated consts cannot be referenced in patterns") } + PatternError::ConstParamInPattern(span) => { + self.span_e0158(span, "const parameters cannot be referenced in patterns") + } PatternError::FloatBug => { // FIXME(#31407) this is only necessary because float parsing is buggy ::rustc::mir::interpret::struct_error( @@ -142,8 +144,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { } fn check_in_cx(&self, hir_id: HirId, f: impl FnOnce(MatchCheckCtxt<'_, 'tcx>)) { - let module = self.tcx.hir().get_module_parent(hir_id); - MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |cx| f(cx)); + let module = self.tcx.parent_module(hir_id); + MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module.to_def_id(), |cx| f(cx)); } fn check_match( @@ -659,7 +661,7 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_ }); if !conflicts_ref.is_empty() { let occurs_because = format!( - "move occurs because `{}` has type `{}` which does implement the `Copy` trait", + "move occurs because `{}` has type `{}` which does not implement the `Copy` trait", name, tables.node_type(pat.hir_id), ); @@ -750,9 +752,9 @@ fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pa } impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> { - type Map = Map<'v>; + type Map = intravisit::ErasedMap<'v>; - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs index 5fbe764430c..ae951e810e3 100644 --- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs @@ -1,14 +1,13 @@ -use rustc::infer::InferCtxt; -use rustc::lint; use rustc::mir::Field; -use rustc::traits::predicate_for_trait_def; -use rustc::traits::{self, ObligationCause, PredicateObligation}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; - use rustc_index::vec::Idx; - +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_session::lint; use rustc_span::Span; +use rustc_trait_selection::traits::predicate_for_trait_def; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; use std::cell::Cell; @@ -181,7 +180,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { let kind = match cv.ty.kind { ty::Float(_) => { tcx.struct_span_lint_hir( - ::rustc::lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, id, span, |lint| lint.build("floating-point types cannot be used in patterns").emit(), diff --git a/src/librustc_mir_build/hair/pattern/mod.rs b/src/librustc_mir_build/hair/pattern/mod.rs index bd8a9877719..6786c356293 100644 --- a/src/librustc_mir_build/hair/pattern/mod.rs +++ b/src/librustc_mir_build/hair/pattern/mod.rs @@ -16,6 +16,7 @@ use rustc::ty::layout::VariantIdx; use rustc::ty::subst::{GenericArg, SubstsRef}; use rustc::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType}; use rustc::ty::{CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations}; +use rustc_ast::ast; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -23,7 +24,6 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::RangeEnd; use rustc_index::vec::Idx; use rustc_span::{Span, DUMMY_SP}; -use syntax::ast; use std::cmp::Ordering; use std::fmt; @@ -31,6 +31,7 @@ use std::fmt; #[derive(Clone, Debug)] crate enum PatternError { AssocConstInPattern(Span), + ConstParamInPattern(Span), StaticInPattern(Span), FloatBug, NonConstPath(Span), @@ -727,7 +728,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { | Res::SelfCtor(..) => PatKind::Leaf { subpatterns }, _ => { - self.errors.push(PatternError::NonConstPath(span)); + let pattern_error = match res { + Res::Def(DefKind::ConstParam, _) => PatternError::ConstParamInPattern(span), + _ => PatternError::NonConstPath(span), + }; + self.errors.push(pattern_error); PatKind::Wild } }; @@ -769,7 +774,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Some(span), ) { Ok(value) => { - let pattern = self.const_to_pat(value, id, span); + let const_ = + ty::Const::from_value(self.tcx, value, self.tables.node_type(id)); + + let pattern = self.const_to_pat(&const_, id, span); if !is_associated_const { return pattern; } @@ -789,7 +797,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { user_ty_span: span, }, }), - ty: value.ty, + ty: const_.ty, } } else { pattern @@ -843,6 +851,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { PatKind::Wild } Err(LitToConstError::Reported) => PatKind::Wild, + Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } } } diff --git a/src/librustc_mir_build/lib.rs b/src/librustc_mir_build/lib.rs index 3c35827d15d..5a8b5a32963 100644 --- a/src/librustc_mir_build/lib.rs +++ b/src/librustc_mir_build/lib.rs @@ -4,6 +4,9 @@ #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(const_if_match)] +#![feature(const_fn)] +#![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(bool_to_option)] #![recursion_limit = "256"] diff --git a/src/librustc_mir_build/lints.rs b/src/librustc_mir_build/lints.rs index 0017f800de7..8b1ddf7461a 100644 --- a/src/librustc_mir_build/lints.rs +++ b/src/librustc_mir_build/lints.rs @@ -1,11 +1,11 @@ use rustc::hir::map::blocks::FnLikeNode; -use rustc::lint::builtin::UNCONDITIONAL_RECURSION; use rustc::mir::{self, Body, TerminatorKind}; use rustc::ty::subst::InternalSubsts; use rustc::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::FnKind; use rustc_index::bit_set::BitSet; +use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId) { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); diff --git a/src/librustc_parse/Cargo.toml b/src/librustc_parse/Cargo.toml index 176bb58ad27..b02cabab0a8 100644 --- a/src/librustc_parse/Cargo.toml +++ b/src/librustc_parse/Cargo.toml @@ -21,5 +21,5 @@ rustc_errors = { path = "../librustc_errors" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } rustc_session = { path = "../librustc_session" } rustc_span = { path = "../librustc_span" } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } unicode-normalization = "0.1.11" diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index e60f1138ddc..6c0b2c40c76 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -1,12 +1,12 @@ +use rustc_ast::token::{self, Token, TokenKind}; +use rustc_ast::util::comments; use rustc_data_structures::sync::Lrc; -use rustc_errors::{DiagnosticBuilder, FatalError}; +use rustc_errors::{error_code, DiagnosticBuilder, FatalError}; use rustc_lexer::unescape; use rustc_lexer::Base; use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{BytePos, Pos, Span}; -use syntax::token::{self, Token, TokenKind}; -use syntax::util::comments; use log::debug; use std::char; @@ -46,12 +46,20 @@ impl<'a> StringReader<'a> { source_file: Lrc, override_span: Option, ) -> Self { - if source_file.src.is_none() { + // Make sure external source is loaded first, before accessing it. + // While this can't show up during normal parsing, `retokenize` may + // be called with a source file from an external crate. + sess.source_map().ensure_source_file_source_present(source_file.clone()); + + // FIXME(eddyb) use `Lrc` or similar to avoid cloning the `String`. + let src = if let Some(src) = &source_file.src { + src.clone() + } else if let Some(src) = source_file.external_src.borrow().get_source() { + src.clone() + } else { sess.span_diagnostic .bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); - } - - let src = (*source_file.src.as_ref().unwrap()).clone(); + }; StringReader { sess, @@ -172,7 +180,7 @@ impl<'a> StringReader<'a> { } /// Turns simple `rustc_lexer::TokenKind` enum into a rich - /// `libsyntax::TokenKind`. This turns strings into interned + /// `librustc_ast::TokenKind`. This turns strings into interned /// symbols and runs additional validation. fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> TokenKind { match token { @@ -327,8 +335,7 @@ impl<'a> StringReader<'a> { match kind { rustc_lexer::LiteralKind::Char { terminated } => { if !terminated { - self.fatal_span_(start, suffix_start, "unterminated character literal".into()) - .raise() + self.fatal_span_(start, suffix_start, "unterminated character literal").raise() } let content_start = start + BytePos(1); let content_end = suffix_start - BytePos(1); @@ -338,12 +345,8 @@ impl<'a> StringReader<'a> { } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { - self.fatal_span_( - start + BytePos(1), - suffix_start, - "unterminated byte constant".into(), - ) - .raise() + self.fatal_span_(start + BytePos(1), suffix_start, "unterminated byte constant") + .raise() } let content_start = start + BytePos(2); let content_end = suffix_start - BytePos(1); @@ -353,7 +356,7 @@ impl<'a> StringReader<'a> { } rustc_lexer::LiteralKind::Str { terminated } => { if !terminated { - self.fatal_span_(start, suffix_start, "unterminated double quote string".into()) + self.fatal_span_(start, suffix_start, "unterminated double quote string") .raise() } let content_start = start + BytePos(1); @@ -367,7 +370,7 @@ impl<'a> StringReader<'a> { self.fatal_span_( start + BytePos(1), suffix_start, - "unterminated double quote byte string".into(), + "unterminated double quote byte string", ) .raise() } @@ -500,7 +503,11 @@ impl<'a> StringReader<'a> { } fn report_unterminated_raw_string(&self, start: BytePos, n_hashes: usize) -> ! { - let mut err = self.struct_span_fatal(start, start, "unterminated raw string"); + let mut err = self.sess.span_diagnostic.struct_span_fatal_with_code( + self.mk_sp(start, start), + "unterminated raw string", + error_code!(E0748), + ); err.span_label(self.mk_sp(start, start), "unterminated raw string"); if n_hashes > 0 { diff --git a/src/librustc_parse/lexer/tokentrees.rs b/src/librustc_parse/lexer/tokentrees.rs index c28b59a7908..b65b8941728 100644 --- a/src/librustc_parse/lexer/tokentrees.rs +++ b/src/librustc_parse/lexer/tokentrees.rs @@ -1,15 +1,15 @@ use super::{StringReader, UnmatchedBrace}; -use rustc_ast_pretty::pprust::token_to_string; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::PResult; -use rustc_span::Span; -use syntax::token::{self, Token}; -use syntax::tokenstream::{ +use rustc_ast::token::{self, Token}; +use rustc_ast::tokenstream::{ DelimSpan, IsJoint::{self, *}, TokenStream, TokenTree, TreeAndJoint, }; +use rustc_ast_pretty::pprust::token_to_string; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::PResult; +use rustc_span::Span; impl<'a> StringReader<'a> { crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { @@ -40,6 +40,7 @@ struct TokenTreesReader<'a> { /// Used only for error recovery when arriving to EOF with mismatched braces. matching_delim_spans: Vec<(token::DelimToken, Span, Span)>, last_unclosed_found_span: Option, + /// Collect empty block spans that might have been auto-inserted by editors. last_delim_empty_block_spans: FxHashMap, } @@ -93,10 +94,8 @@ impl<'a> TokenTreesReader<'a> { } if let Some((delim, _)) = self.open_braces.last() { - if let Some((_, open_sp, close_sp)) = self - .matching_delim_spans - .iter() - .filter(|(d, open_sp, close_sp)| { + if let Some((_, open_sp, close_sp)) = + self.matching_delim_spans.iter().find(|(d, open_sp, close_sp)| { if let Some(close_padding) = sm.span_to_margin(*close_sp) { if let Some(open_padding) = sm.span_to_margin(*open_sp) { return delim == d && close_padding != open_padding; @@ -104,7 +103,6 @@ impl<'a> TokenTreesReader<'a> { } false }) - .next() // these are in reverse order as they get inserted on close, but { // we want the last open/first close @@ -141,10 +139,14 @@ impl<'a> TokenTreesReader<'a> { if tts.is_empty() { let empty_block_span = open_brace_span.to(close_brace_span); - self.last_delim_empty_block_spans.insert(delim, empty_block_span); + if !sm.is_multiline(empty_block_span) { + // Only track if the block is in the form of `{}`, otherwise it is + // likely that it was written on purpose. + self.last_delim_empty_block_spans.insert(delim, empty_block_span); + } } - if self.open_braces.len() == 0 { + if self.open_braces.is_empty() { // Clear up these spans to avoid suggesting them as we've found // properly matched delimiters so far for an entire block. self.matching_delim_spans.clear(); @@ -212,7 +214,7 @@ impl<'a> TokenTreesReader<'a> { _ => {} } - Ok(TokenTree::Delimited(delim_span, delim, tts.into()).into()) + Ok(TokenTree::Delimited(delim_span, delim, tts).into()) } token::CloseDelim(delim) => { // An unexpected closing delimiter (i.e., there is no diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 4aad2c0f68a..c31cc1b4c9f 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -2,17 +2,19 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] +#![feature(bindings_after_at)] +#![feature(try_blocks)] +use rustc_ast::ast; +use rustc_ast::token::{self, Nonterminal}; +use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; -use syntax::ast; -use syntax::token::{self, Nonterminal}; -use syntax::tokenstream::{self, TokenStream, TokenTree}; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::str; use log::info; @@ -24,24 +26,6 @@ pub mod parser; use parser::{emit_unclosed_delims, make_unclosed_delims_error, Parser}; pub mod lexer; pub mod validate_attr; -#[macro_use] -pub mod config; - -#[derive(Clone)] -pub struct Directory { - pub path: PathBuf, - pub ownership: DirectoryOwnership, -} - -#[derive(Copy, Clone)] -pub enum DirectoryOwnership { - Owned { - // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`. - relative: Option, - }, - UnownedViaBlock, - UnownedViaMod, -} // A bunch of utility functions of the form `parse__from_` // where includes crate, expr, item, stmt, tts, and one that @@ -118,10 +102,7 @@ pub fn maybe_new_parser_from_source_str( name: FileName, source: String, ) -> Result, Vec> { - let mut parser = - maybe_source_file_to_parser(sess, sess.source_map().new_source_file(name, source))?; - parser.recurse_into_file_modules = false; - Ok(parser) + maybe_source_file_to_parser(sess, sess.source_map().new_source_file(name, source)) } /// Creates a new parser, handling errors as appropriate if the file doesn't exist. @@ -145,12 +126,10 @@ pub fn maybe_new_parser_from_file<'a>( pub fn new_sub_parser_from_file<'a>( sess: &'a ParseSess, path: &Path, - directory_ownership: DirectoryOwnership, module_name: Option, sp: Span, ) -> Parser<'a> { let mut p = source_file_to_parser(sess, file_to_source_file(sess, path, Some(sp))); - p.directory.ownership = directory_ownership; p.root_module_name = module_name; p } @@ -170,7 +149,7 @@ fn maybe_source_file_to_parser( let (stream, unclosed_delims) = maybe_file_to_stream(sess, source_file, None)?; let mut parser = stream_to_parser(sess, stream, None); parser.unclosed_delims = unclosed_delims; - if parser.token == token::Eof && parser.token.span.is_dummy() { + if parser.token == token::Eof { parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt()); } @@ -256,26 +235,7 @@ pub fn stream_to_parser<'a>( stream: TokenStream, subparser_name: Option<&'static str>, ) -> Parser<'a> { - Parser::new(sess, stream, None, true, false, subparser_name) -} - -/// Given a stream, the `ParseSess` and the base directory, produces a parser. -/// -/// Use this function when you are creating a parser from the token stream -/// and also care about the current working directory of the parser (e.g., -/// you are trying to resolve modules defined inside a macro invocation). -/// -/// # Note -/// -/// The main usage of this function is outside of rustc, for those who uses -/// libsyntax as a library. Please do not remove this function while refactoring -/// just because it is not used in rustc codebase! -pub fn stream_to_parser_with_base_dir<'a>( - sess: &'a ParseSess, - stream: TokenStream, - base_dir: Directory, -) -> Parser<'a> { - Parser::new(sess, stream, Some(base_dir), true, false, None) + Parser::new(sess, stream, false, subparser_name) } /// Runs the given subparser `f` on the tokens of the given `attr`'s item. @@ -285,7 +245,7 @@ pub fn parse_in<'a, T>( name: &'static str, mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, T> { - let mut parser = Parser::new(sess, tts, None, false, false, Some(name)); + let mut parser = Parser::new(sess, tts, false, Some(name)); let result = f(&mut parser)?; if parser.token != token::Eof { parser.unexpected()?; @@ -313,9 +273,6 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke Nonterminal::NtItem(ref item) => { prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) } - Nonterminal::NtTraitItem(ref item) | Nonterminal::NtImplItem(ref item) => { - prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) - } Nonterminal::NtIdent(ident, is_raw) => { Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) } @@ -373,7 +330,7 @@ fn prepend_attrs( span: rustc_span::Span, ) -> Option { let tokens = tokens?; - if attrs.len() == 0 { + if attrs.is_empty() { return Some(tokens.clone()); } let mut builder = tokenstream::TokenStreamBuilder::new(); @@ -422,7 +379,7 @@ fn prepend_attrs( builder.push(tokenstream::TokenTree::Delimited( delim_span, token::DelimToken::Bracket, - brackets.build().into(), + brackets.build(), )); } builder.push(tokens.clone()); diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index 905f6bef58e..b56dd30739d 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -1,23 +1,29 @@ -use super::{Parser, PathStyle, TokenType}; +use super::{Parser, PathStyle}; +use rustc_ast::ast; +use rustc_ast::attr; +use rustc_ast::token::{self, Nonterminal}; +use rustc_ast::util::comments; use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_span::{Span, Symbol}; -use syntax::ast; -use syntax::attr; -use syntax::token::{self, Nonterminal}; -use syntax::util::comments; use log::debug; #[derive(Debug)] -enum InnerAttributeParsePolicy<'a> { +pub(super) enum InnerAttrPolicy<'a> { Permitted, - NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option }, + Forbidden { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option }, } const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ permitted in this context"; +pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden { + reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, + saw_doc_comment: false, + prev_attr_sp: None, +}; + impl<'a> Parser<'a> { /// Parses attributes that appear before an item. pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec> { @@ -25,48 +31,44 @@ impl<'a> Parser<'a> { let mut just_parsed_doc_comment = false; loop { debug!("parse_outer_attributes: self.token={:?}", self.token); - match self.token.kind { - token::Pound => { - let inner_error_reason = if just_parsed_doc_comment { - "an inner attribute is not permitted following an outer doc comment" - } else if !attrs.is_empty() { - "an inner attribute is not permitted following an outer attribute" - } else { - DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG - }; - let inner_parse_policy = InnerAttributeParsePolicy::NotPermitted { - reason: inner_error_reason, - saw_doc_comment: just_parsed_doc_comment, - prev_attr_sp: attrs.last().and_then(|a| Some(a.span)), - }; - let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; - attrs.push(attr); - just_parsed_doc_comment = false; - } - token::DocComment(s) => { - let attr = self.mk_doc_comment(s); - if attr.style != ast::AttrStyle::Outer { - let span = self.token.span; - let mut err = self.struct_span_err(span, "expected outer doc comment"); - err.note( + if self.check(&token::Pound) { + let inner_error_reason = if just_parsed_doc_comment { + "an inner attribute is not permitted following an outer doc comment" + } else if !attrs.is_empty() { + "an inner attribute is not permitted following an outer attribute" + } else { + DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG + }; + let inner_parse_policy = InnerAttrPolicy::Forbidden { + reason: inner_error_reason, + saw_doc_comment: just_parsed_doc_comment, + prev_attr_sp: attrs.last().map(|a| a.span), + }; + let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; + attrs.push(attr); + just_parsed_doc_comment = false; + } else if let token::DocComment(s) = self.token.kind { + let attr = self.mk_doc_comment(s); + if attr.style != ast::AttrStyle::Outer { + self.struct_span_err(self.token.span, "expected outer doc comment") + .note( "inner doc comments like this (starting with \ - `//!` or `/*!`) can only appear before items", - ); - return Err(err); - } - attrs.push(attr); - self.bump(); - just_parsed_doc_comment = true; + `//!` or `/*!`) can only appear before items", + ) + .emit(); } - _ => break, + attrs.push(attr); + self.bump(); + just_parsed_doc_comment = true; + } else { + break; } } Ok(attrs) } fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute { - let style = comments::doc_comment_style(&s.as_str()); - attr::mk_doc_comment(style, s, self.token.span) + attr::mk_doc_comment(comments::doc_comment_style(&s.as_str()), s, self.token.span) } /// Matches `attribute = # ! [ meta_item ]`. @@ -75,96 +77,67 @@ impl<'a> Parser<'a> { /// attribute. pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> { debug!("parse_attribute: permit_inner={:?} self.token={:?}", permit_inner, self.token); - let inner_parse_policy = if permit_inner { - InnerAttributeParsePolicy::Permitted - } else { - InnerAttributeParsePolicy::NotPermitted { - reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, - saw_doc_comment: false, - prev_attr_sp: None, - } - }; + let inner_parse_policy = + if permit_inner { InnerAttrPolicy::Permitted } else { DEFAULT_INNER_ATTR_FORBIDDEN }; self.parse_attribute_with_inner_parse_policy(inner_parse_policy) } - /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy` + /// The same as `parse_attribute`, except it takes in an `InnerAttrPolicy` /// that prescribes how to handle inner attributes. fn parse_attribute_with_inner_parse_policy( &mut self, - inner_parse_policy: InnerAttributeParsePolicy<'_>, + inner_parse_policy: InnerAttrPolicy<'_>, ) -> PResult<'a, ast::Attribute> { debug!( "parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token ); - let (span, item, style) = match self.token.kind { - token::Pound => { - let lo = self.token.span; - self.bump(); - - if let InnerAttributeParsePolicy::Permitted = inner_parse_policy { - self.expected_tokens.push(TokenType::Token(token::Not)); - } - - let style = if self.token == token::Not { - self.bump(); - ast::AttrStyle::Inner - } else { - ast::AttrStyle::Outer - }; + let lo = self.token.span; + let (span, item, style) = if self.eat(&token::Pound) { + let style = + if self.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer }; - self.expect(&token::OpenDelim(token::Bracket))?; - let item = self.parse_attr_item()?; - self.expect(&token::CloseDelim(token::Bracket))?; - let hi = self.prev_span; - - let attr_sp = lo.to(hi); - - // Emit error if inner attribute is encountered and not permitted - if style == ast::AttrStyle::Inner { - if let InnerAttributeParsePolicy::NotPermitted { - reason, - saw_doc_comment, - prev_attr_sp, - } = inner_parse_policy - { - let prev_attr_note = if saw_doc_comment { - "previous doc comment" - } else { - "previous outer attribute" - }; - - let mut diagnostic = self.struct_span_err(attr_sp, reason); - - if let Some(prev_attr_sp) = prev_attr_sp { - diagnostic - .span_label(attr_sp, "not permitted following an outer attibute") - .span_label(prev_attr_sp, prev_attr_note); - } - - diagnostic - .note( - "inner attributes, like `#![no_std]`, annotate the item \ - enclosing them, and are usually found at the beginning of \ - source files. Outer attributes, like `#[test]`, annotate the \ - item following them.", - ) - .emit(); - } - } + self.expect(&token::OpenDelim(token::Bracket))?; + let item = self.parse_attr_item()?; + self.expect(&token::CloseDelim(token::Bracket))?; + let attr_sp = lo.to(self.prev_token.span); - (attr_sp, item, style) - } - _ => { - let token_str = pprust::token_to_string(&self.token); - let msg = &format!("expected `#`, found `{}`", token_str); - return Err(self.struct_span_err(self.token.span, msg)); + // Emit error if inner attribute is encountered and forbidden. + if style == ast::AttrStyle::Inner { + self.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy); } + + (attr_sp, item, style) + } else { + let token_str = pprust::token_to_string(&self.token); + let msg = &format!("expected `#`, found `{}`", token_str); + return Err(self.struct_span_err(self.token.span, msg)); }; Ok(attr::mk_attr_from_item(style, item, span)) } + pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) { + if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy { + let prev_attr_note = + if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" }; + + let mut diag = self.struct_span_err(attr_sp, reason); + + if let Some(prev_attr_sp) = prev_attr_sp { + diag.span_label(attr_sp, "not permitted following an outer attribute") + .span_label(prev_attr_sp, prev_attr_note); + } + + diag.note( + "inner attributes, like `#![no_std]`, annotate the item enclosing them, \ + and are usually found at the beginning of source files. \ + Outer attributes, like `#[test]`, annotate the item following them.", + ) + .emit(); + } + } + /// Parses an inner part of an attribute (the path and following tokens). /// The tokens must be either a delimited token stream, or empty token stream, /// or the "legacy" key-value form. @@ -200,28 +173,22 @@ impl<'a> Parser<'a> { crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec> { let mut attrs: Vec = vec![]; loop { - match self.token.kind { - token::Pound => { - // Don't even try to parse if it's not an inner attribute. - if !self.look_ahead(1, |t| t == &token::Not) { - break; - } - - let attr = self.parse_attribute(true)?; - assert_eq!(attr.style, ast::AttrStyle::Inner); + // Only try to parse if it is an inner attribute (has `!`). + if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) { + let attr = self.parse_attribute(true)?; + assert_eq!(attr.style, ast::AttrStyle::Inner); + attrs.push(attr); + } else if let token::DocComment(s) = self.token.kind { + // We need to get the position of this token before we bump. + let attr = self.mk_doc_comment(s); + if attr.style == ast::AttrStyle::Inner { attrs.push(attr); + self.bump(); + } else { + break; } - token::DocComment(s) => { - // We need to get the position of this token before we bump. - let attr = self.mk_doc_comment(s); - if attr.style == ast::AttrStyle::Inner { - attrs.push(attr); - self.bump(); - } else { - break; - } - } - _ => break, + } else { + break; } } Ok(attrs) @@ -232,12 +199,10 @@ impl<'a> Parser<'a> { debug!("checking if {:?} is unusuffixed", lit); if !lit.kind.is_unsuffixed() { - let msg = "suffixed literals are not allowed in attributes"; - self.struct_span_err(lit.span, msg) + self.struct_span_err(lit.span, "suffixed literals are not allowed in attributes") .help( - "instead of using a suffixed literal \ - (`1u8`, `1.0f32`, etc.), use an unsuffixed version \ - (`1`, `1.0`, etc.)", + "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \ + use an unsuffixed version (`1`, `1.0`, etc.)", ) .emit(); } @@ -255,7 +220,7 @@ impl<'a> Parser<'a> { while self.token.kind != token::Eof { let lo = self.token.span; let item = self.parse_attr_item()?; - expanded_attrs.push((item, lo.to(self.prev_span))); + expanded_attrs.push((item, lo.to(self.prev_token.span))); if !self.eat(&token::Comma) { break; } @@ -303,7 +268,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; let path = self.parse_path(PathStyle::Mod)?; let kind = self.parse_meta_item_kind()?; - let span = lo.to(self.prev_span); + let span = lo.to(self.prev_token.span); Ok(ast::MetaItem { path, kind, span }) } diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 018aef3c13c..87255386b9e 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1,6 +1,13 @@ use super::ty::AllowPlus; use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType}; +use rustc_ast::ast::{ + self, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, Param, +}; +use rustc_ast::ast::{AttrVec, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind}; +use rustc_ast::ptr::P; +use rustc_ast::token::{self, TokenKind}; +use rustc_ast::util::parser::AssocOp; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err}; @@ -8,18 +15,11 @@ use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult}; use rustc_span::source_map::Spanned; use rustc_span::symbol::kw; use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP}; -use syntax::ast::{ - self, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, Param, -}; -use syntax::ast::{AttrVec, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind}; -use syntax::ptr::P; -use syntax::token::{self, token_can_begin_expr, TokenKind}; -use syntax::util::parser::AssocOp; use log::{debug, trace}; use std::mem; -const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments"; +const TURBOFISH: &str = "use `::<...>` instead of `<...>` to specify type arguments"; /// Creates a placeholder argument. pub(super) fn dummy_arg(ident: Ident) -> Param { @@ -40,55 +40,12 @@ pub(super) fn dummy_arg(ident: Ident) -> Param { } pub enum Error { - FileNotFoundForModule { - mod_name: String, - default_path: String, - secondary_path: String, - dir_path: String, - }, - DuplicatePaths { - mod_name: String, - default_path: String, - secondary_path: String, - }, UselessDocComment, } impl Error { fn span_err(self, sp: impl Into, handler: &Handler) -> DiagnosticBuilder<'_> { match self { - Error::FileNotFoundForModule { - ref mod_name, - ref default_path, - ref secondary_path, - ref dir_path, - } => { - let mut err = struct_span_err!( - handler, - sp, - E0583, - "file not found for module `{}`", - mod_name, - ); - err.help(&format!( - "name the file either {} or {} inside the directory \"{}\"", - default_path, secondary_path, dir_path, - )); - err - } - Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => { - let mut err = struct_span_err!( - handler, - sp, - E0584, - "file for module `{}` found at both {} and {}", - mod_name, - default_path, - secondary_path, - ); - err.help("delete or rename one of them to remove the ambiguity"); - err - } Error::UselessDocComment => { let mut err = struct_span_err!( handler, @@ -192,17 +149,19 @@ impl<'a> Parser<'a> { TokenKind::CloseDelim(token::DelimToken::Brace), TokenKind::CloseDelim(token::DelimToken::Paren), ]; - if let token::Ident(name, false) = self.token.kind { - if Ident::new(name, self.token.span).is_raw_guess() - && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) + match self.token.ident() { + Some((ident, false)) + if ident.is_raw_guess() + && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) => { err.span_suggestion( - self.token.span, + ident.span, "you can escape reserved keywords to use them as identifiers", - format!("r#{}", name), + format!("r#{}", ident.name), Applicability::MaybeIncorrect, ); } + _ => {} } if let Some(token_descr) = super::token_descr_opt(&self.token) { err.span_label(self.token.span, format!("expected identifier, found {}", token_descr)); @@ -260,24 +219,24 @@ impl<'a> Parser<'a> { }; ( format!("expected one of {}, found {}", expect, actual), - (self.prev_span.shrink_to_hi(), format!("expected one of {}", short_expect)), + (self.prev_token.span.shrink_to_hi(), format!("expected one of {}", short_expect)), ) } else if expected.is_empty() { ( format!("unexpected token: {}", actual), - (self.prev_span, "unexpected token after this".to_string()), + (self.prev_token.span, "unexpected token after this".to_string()), ) } else { ( format!("expected {}, found {}", expect, actual), - (self.prev_span.shrink_to_hi(), format!("expected {}", expect)), + (self.prev_token.span.shrink_to_hi(), format!("expected {}", expect)), ) }; self.last_unexpected_token_span = Some(self.token.span); let mut err = self.struct_span_err(self.token.span, &msg_exp); let sp = if self.token == token::Eof { // This is EOF; don't want to point at the following char, but rather the last token. - self.prev_span + self.prev_token.span } else { label_sp }; @@ -298,7 +257,7 @@ impl<'a> Parser<'a> { } let sm = self.sess.source_map(); - if self.prev_span == DUMMY_SP { + if self.prev_token.span == DUMMY_SP { // Account for macro context where the previous span might not be // available to avoid incorrect output (#54841). err.span_label(self.token.span, label_exp); @@ -577,7 +536,7 @@ impl<'a> Parser<'a> { match inner_op.kind { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { // Respan to include both operators. - let op_span = op.span.to(self.prev_span); + let op_span = op.span.to(self.prev_token.span); let mut err = self.struct_span_err(op_span, "comparison operators cannot be chained"); @@ -632,7 +591,7 @@ impl<'a> Parser<'a> { // FIXME: actually check that the two expressions in the binop are // paths and resynthesize new fn call expression instead of using // `ExprKind::Err` placeholder. - mk_err_expr(self, inner_op.span.to(self.prev_span)) + mk_err_expr(self, inner_op.span.to(self.prev_token.span)) } Err(mut expr_err) => { expr_err.cancel(); @@ -654,7 +613,7 @@ impl<'a> Parser<'a> { // FIXME: actually check that the two expressions in the binop are // paths and resynthesize new fn call expression instead of using // `ExprKind::Err` placeholder. - mk_err_expr(self, inner_op.span.to(self.prev_span)) + mk_err_expr(self, inner_op.span.to(self.prev_token.span)) } } } else { @@ -723,7 +682,7 @@ impl<'a> Parser<'a> { self.bump(); // `+` let bounds = self.parse_generic_bounds(None)?; - let sum_span = ty.span.to(self.prev_span); + let sum_span = ty.span.to(self.prev_token.span); let mut err = struct_span_err!( self.sess.span_diagnostic, @@ -790,7 +749,7 @@ impl<'a> Parser<'a> { let mut path = ast::Path { segments: Vec::new(), span: DUMMY_SP }; self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; - path.span = ty_span.to(self.prev_span); + path.span = ty_span.to(self.prev_token.span); let ty_str = self.span_to_snippet(ty_span).unwrap_or_else(|_| pprust::ty_to_string(&ty)); self.struct_span_err(path.span, "missing angle brackets in associated item path") @@ -809,9 +768,9 @@ impl<'a> Parser<'a> { pub(super) fn maybe_consume_incorrect_semicolon(&mut self, items: &[P]) -> bool { if self.eat(&token::Semi) { - let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`"); + let mut err = self.struct_span_err(self.prev_token.span, "expected item, found `;`"); err.span_suggestion_short( - self.prev_span, + self.prev_token.span, "remove this semicolon", String::new(), Applicability::MachineApplicable, @@ -854,10 +813,10 @@ impl<'a> Parser<'a> { } // We don't want to point at the following span after DUMMY_SP. // This happens when the parser finds an empty TokenStream. - _ if self.prev_span == DUMMY_SP => (self.token.span, self.token.span), + _ if self.prev_token.span == DUMMY_SP => (self.token.span, self.token.span), // EOF, don't want to point at the following char, but rather the last token. - (token::Eof, None) => (self.prev_span, self.token.span), - _ => (self.prev_span.shrink_to_hi(), self.token.span), + (token::Eof, None) => (self.prev_token.span, self.token.span), + _ => (self.prev_token.span.shrink_to_hi(), self.token.span), }; let msg = format!( "expected `{}`, found {}", @@ -894,14 +853,13 @@ impl<'a> Parser<'a> { let sm = self.sess.source_map(); let msg = format!("expected `;`, found `{}`", super::token_descr(&self.token)); let appl = Applicability::MachineApplicable; - if self.token.span == DUMMY_SP || self.prev_span == DUMMY_SP { - // Likely inside a macro, can't provide meaninful suggestions. + if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP { + // Likely inside a macro, can't provide meaningful suggestions. return self.expect(&token::Semi).map(drop); - } else if !sm.is_multiline(self.prev_span.until(self.token.span)) { + } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) { // The current token is in the same line as the prior token, not recoverable. } else if self.look_ahead(1, |t| { - t == &token::CloseDelim(token::Brace) - || token_can_begin_expr(t) && t.kind != token::Colon + t == &token::CloseDelim(token::Brace) || t.can_begin_expr() && t.kind != token::Colon }) && [token::Comma, token::Colon].contains(&self.token.kind) { // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is @@ -911,7 +869,7 @@ impl<'a> Parser<'a> { // let x = 32: // let y = 42; self.bump(); - let sp = self.prev_span; + let sp = self.prev_token.span; self.struct_span_err(sp, &msg) .span_suggestion(sp, "change this to `;`", ";".to_string(), appl) .emit(); @@ -919,7 +877,7 @@ impl<'a> Parser<'a> { } else if self.look_ahead(0, |t| { t == &token::CloseDelim(token::Brace) || ( - token_can_begin_expr(t) && t != &token::Semi && t != &token::Pound + t.can_begin_expr() && t != &token::Semi && t != &token::Pound // Avoid triggering with too many trailing `#` in raw string. ) }) { @@ -928,7 +886,7 @@ impl<'a> Parser<'a> { // // let x = 32 // let y = 42; - let sp = self.prev_span.shrink_to_hi(); + let sp = self.prev_token.span.shrink_to_hi(); self.struct_span_err(sp, &msg) .span_label(self.token.span, "unexpected token") .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl) @@ -962,7 +920,7 @@ impl<'a> Parser<'a> { self.expect(&token::OpenDelim(token::Paren))?; let expr = self.parse_expr()?; self.expect(&token::CloseDelim(token::Paren))?; - Ok((self.prev_span, expr, false)) + Ok((self.prev_token.span, expr, false)) } fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, P, bool)> { @@ -1037,10 +995,10 @@ impl<'a> Parser<'a> { .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap()) .unwrap_or_else(|_| pprust::pat_to_string(&pat)); - self.struct_span_err(self.prev_span, "unexpected closing `)`") + self.struct_span_err(self.prev_token.span, "unexpected closing `)`") .span_label(begin_par_sp, "opening `(`") .span_suggestion( - begin_par_sp.to(self.prev_span), + begin_par_sp.to(self.prev_token.span), "remove parenthesis in `for` loop", format!("{} in {}", pat_str, pprust::expr_to_string(&expr)), // With e.g. `for (x) in y)` this would replace `(x) in y)` @@ -1092,7 +1050,7 @@ impl<'a> Parser<'a> { err.emit(); // Recover from parse error, callers expect the closing delim to be consumed. self.consume_block(delim, ConsumeClosingDelim::Yes); - self.mk_expr(lo.to(self.prev_span), ExprKind::Err, AttrVec::new()) + self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err, AttrVec::new()) } } } @@ -1139,7 +1097,7 @@ impl<'a> Parser<'a> { err.span_label(sp, "unclosed delimiter"); } err.span_suggestion_short( - self.prev_span.shrink_to_hi(), + self.prev_token.span.shrink_to_hi(), &format!("{} may belong here", delim.to_string()), delim.to_string(), Applicability::MaybeIncorrect, @@ -1247,9 +1205,9 @@ impl<'a> Parser<'a> { pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) { if self.eat_keyword(kw::In) { // a common typo: `for _ in in bar {}` - self.struct_span_err(self.prev_span, "expected iterable, found keyword `in`") + self.struct_span_err(self.prev_token.span, "expected iterable, found keyword `in`") .span_suggestion_short( - in_span.until(self.prev_span), + in_span.until(self.prev_token.span), "remove the duplicated `in`", String::new(), Applicability::MachineApplicable, diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 5a4225ece65..c65e99842c5 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -4,21 +4,19 @@ use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use crate::maybe_recover_from_interpolated_ty_qpath; +use rustc_ast::ast::{self, AttrStyle, AttrVec, CaptureBy, Field, Ident, Lit, UnOp, DUMMY_NODE_ID}; +use rustc_ast::ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}; +use rustc_ast::ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; +use rustc_ast::ptr::P; +use rustc_ast::token::{self, Token, TokenKind}; +use rustc_ast::util::classify; +use rustc_ast::util::literal::LitError; +use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, PResult}; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{kw, sym, Symbol}; use std::mem; -use syntax::ast::{self, AttrStyle, AttrVec, CaptureBy, Field, Ident, Lit, DUMMY_NODE_ID}; -use syntax::ast::{ - AnonConst, BinOp, BinOpKind, FnDecl, FunctionRetTy, Mac, Param, Ty, TyKind, UnOp, -}; -use syntax::ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; -use syntax::ptr::P; -use syntax::token::{self, Token, TokenKind}; -use syntax::util::classify; -use syntax::util::literal::LitError; -use syntax::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression /// dropped into the token stream, which happens while parsing the result of @@ -52,7 +50,6 @@ macro_rules! maybe_whole_expr { AttrVec::new(), )); } - // N.B., `NtIdent(ident)` is normalized to `Ident` in `fn bump`. _ => {} }; } @@ -99,15 +96,14 @@ impl<'a> Parser<'a> { fn parse_expr_catch_underscore(&mut self) -> PResult<'a, P> { match self.parse_expr() { Ok(expr) => Ok(expr), - Err(mut err) => match self.token.kind { - token::Ident(name, false) - if name == kw::Underscore && self.look_ahead(1, |t| t == &token::Comma) => + Err(mut err) => match self.token.ident() { + Some((Ident { name: kw::Underscore, .. }, false)) + if self.look_ahead(1, |t| t == &token::Comma) => { // Special-case handling of `foo(_, _, _)` err.emit(); - let sp = self.token.span; self.bump(); - Ok(self.mk_expr(sp, ExprKind::Err, AttrVec::new())) + Ok(self.mk_expr(self.prev_token.span, ExprKind::Err, AttrVec::new())) } _ => Err(err), }, @@ -168,8 +164,8 @@ impl<'a> Parser<'a> { while let Some(op) = self.check_assoc_op() { // Adjust the span for interpolated LHS to point to the `$lhs` token // and not to what it refers to. - let lhs_span = match self.unnormalized_prev_token().kind { - TokenKind::Interpolated(..) => self.prev_span, + let lhs_span = match self.prev_token.kind { + TokenKind::Interpolated(..) => self.prev_token.span, _ => lhs.span, }; @@ -227,12 +223,8 @@ impl<'a> Parser<'a> { // Make sure that the span of the parent node is larger than the span of lhs and rhs, // including the attributes. - let lhs_span = lhs - .attrs - .iter() - .filter(|a| a.style == AttrStyle::Outer) - .next() - .map_or(lhs_span, |a| a.span); + let lhs_span = + lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer).map_or(lhs_span, |a| a.span); let span = lhs_span.to(rhs.span); lhs = match op { AssocOp::Add @@ -338,21 +330,19 @@ impl<'a> Parser<'a> { /// /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively. fn check_assoc_op(&self) -> Option> { - Some(Spanned { - node: match (AssocOp::from_token(&self.token), &self.token.kind) { - (Some(op), _) => op, - (None, token::Ident(sym::and, false)) => { - self.error_bad_logical_op("and", "&&", "conjunction"); - AssocOp::LAnd - } - (None, token::Ident(sym::or, false)) => { - self.error_bad_logical_op("or", "||", "disjunction"); - AssocOp::LOr - } - _ => return None, - }, - span: self.token.span, - }) + let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) { + (Some(op), _) => (op, self.token.span), + (None, Some((Ident { name: sym::and, span }, false))) => { + self.error_bad_logical_op("and", "&&", "conjunction"); + (AssocOp::LAnd, span) + } + (None, Some((Ident { name: sym::or, span }, false))) => { + self.error_bad_logical_op("or", "||", "disjunction"); + (AssocOp::LOr, span) + } + _ => return None, + }; + Some(source_map::respan(span, op)) } /// Error on `and` and `or` suggesting `&&` and `||` respectively. @@ -443,7 +433,7 @@ impl<'a> Parser<'a> { let attrs = self.parse_or_use_outer_attributes(attrs)?; let lo = self.token.span; // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr() - let (hi, ex) = match self.token.kind { + let (hi, ex) = match self.token.uninterpolate().kind { token::Not => self.parse_unary_expr(lo, UnOp::Not), // `!expr` token::Tilde => self.recover_tilde_expr(lo), // `~expr` token::BinOp(token::Minus) => self.parse_unary_expr(lo, UnOp::Neg), // `-expr` @@ -490,7 +480,7 @@ impl<'a> Parser<'a> { } fn is_mistaken_not_ident_negation(&self) -> bool { - let token_cannot_continue_expr = |t: &Token| match t.kind { + let token_cannot_continue_expr = |t: &Token| match t.uninterpolate().kind { // These tokens can start an expression after `!`, but // can't continue an expression after an ident token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw), @@ -529,8 +519,8 @@ impl<'a> Parser<'a> { ) -> PResult<'a, (Span, P)> { expr.map(|e| { ( - match self.unnormalized_prev_token().kind { - TokenKind::Interpolated(..) => self.prev_span, + match self.prev_token.kind { + TokenKind::Interpolated(..) => self.prev_token.span, _ => e.span, }, e, @@ -551,8 +541,8 @@ impl<'a> Parser<'a> { // Save the state of the parser before parsing type normally, in case there is a // LessThan comparison after this cast. let parser_snapshot_before_type = self.clone(); - match self.parse_ty_no_plus() { - Ok(rhs) => Ok(mk_expr(self, rhs)), + let cast_expr = match self.parse_ty_no_plus() { + Ok(rhs) => mk_expr(self, rhs), Err(mut type_err) => { // Rewind to before attempting to parse the type with generics, to recover // from situations like `x as usize < y` in which we first tried to parse @@ -606,22 +596,75 @@ impl<'a> Parser<'a> { ) .emit(); - Ok(expr) + expr } Err(mut path_err) => { // Couldn't parse as a path, return original error and parser state. path_err.cancel(); mem::replace(self, parser_snapshot_after_type); - Err(type_err) + return Err(type_err); } } } - } + }; + + self.parse_and_disallow_postfix_after_cast(cast_expr) + } + + /// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast, + /// then emits an error and returns the newly parsed tree. + /// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`. + fn parse_and_disallow_postfix_after_cast( + &mut self, + cast_expr: P, + ) -> PResult<'a, P> { + // Save the memory location of expr before parsing any following postfix operators. + // This will be compared with the memory location of the output expression. + // If they different we can assume we parsed another expression because the existing expression is not reallocated. + let addr_before = &*cast_expr as *const _ as usize; + let span = cast_expr.span; + let with_postfix = self.parse_dot_or_call_expr_with_(cast_expr, span)?; + let changed = addr_before != &*with_postfix as *const _ as usize; + + // Check if an illegal postfix operator has been added after the cast. + // If the resulting expression is not a cast, or has a different memory location, it is an illegal postfix operator. + if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) || changed { + let msg = format!( + "casts cannot be followed by {}", + match with_postfix.kind { + ExprKind::Index(_, _) => "indexing", + ExprKind::Try(_) => "?", + ExprKind::Field(_, _) => "a field access", + ExprKind::MethodCall(_, _) => "a method call", + ExprKind::Call(_, _) => "a function call", + ExprKind::Await(_) => "`.await`", + _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), + } + ); + let mut err = self.struct_span_err(span, &msg); + // If type ascription is "likely an error", the user will already be getting a useful + // help message, and doesn't need a second. + if self.last_type_ascription.map_or(false, |last_ascription| last_ascription.1) { + self.maybe_annotate_with_ascription(&mut err, false); + } else { + let suggestions = vec![ + (span.shrink_to_lo(), "(".to_string()), + (span.shrink_to_hi(), ")".to_string()), + ]; + err.multipart_suggestion( + "try surrounding the expression in parentheses", + suggestions, + Applicability::MachineApplicable, + ); + } + err.emit(); + }; + Ok(with_postfix) } fn parse_assoc_op_ascribe(&mut self, lhs: P, lhs_span: Span) -> PResult<'a, P> { let maybe_path = self.could_ascription_be_path(&lhs.kind); - self.last_type_ascription = Some((self.prev_span, maybe_path)); + self.last_type_ascription = Some((self.prev_token.span, maybe_path)); let lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?; self.sess.gated_spans.gate(sym::type_ascription, lhs.span); Ok(lhs) @@ -630,10 +673,28 @@ impl<'a> Parser<'a> { /// Parse `& mut? ` or `& raw [ const | mut ] `. fn parse_borrow_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { self.expect_and()?; + let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon); + let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below. let (borrow_kind, mutbl) = self.parse_borrow_modifiers(lo); let expr = self.parse_prefix_expr(None); - let (span, expr) = self.interpolated_or_expr_span(expr)?; - Ok((lo.to(span), ExprKind::AddrOf(borrow_kind, mutbl, expr))) + let (hi, expr) = self.interpolated_or_expr_span(expr)?; + let span = lo.to(hi); + if let Some(lt) = lifetime { + self.error_remove_borrow_lifetime(span, lt.ident.span); + } + Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr))) + } + + fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) { + self.struct_span_err(span, "borrow expressions cannot be annotated with lifetimes") + .span_label(lt_span, "annotated with lifetime here") + .span_suggestion( + lt_span, + "remove the lifetime annotation", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); } /// Parse `mut?` or `raw [ const | mut ]`. @@ -643,7 +704,7 @@ impl<'a> Parser<'a> { let found_raw = self.eat_keyword(kw::Raw); assert!(found_raw); let mutability = self.parse_const_or_mut().unwrap(); - self.sess.gated_spans.gate(sym::raw_ref_op, lo.to(self.prev_span)); + self.sess.gated_spans.gate(sym::raw_ref_op, lo.to(self.prev_token.span)); (ast::BorrowKind::Raw, mutability) } else { // `mut?` @@ -672,25 +733,16 @@ impl<'a> Parser<'a> { expr.map(|mut expr| { attrs.extend::>(expr.attrs.into()); expr.attrs = attrs; - self.error_attr_on_if_expr(&expr); expr }) }) } - fn error_attr_on_if_expr(&self, expr: &Expr) { - if let (ExprKind::If(..), [a0, ..]) = (&expr.kind, &*expr.attrs) { - // Just point to the first attribute in there... - self.struct_span_err(a0.span, "attributes are not yet allowed on `if` expressions") - .emit(); - } - } - fn parse_dot_or_call_expr_with_(&mut self, mut e: P, lo: Span) -> PResult<'a, P> { loop { if self.eat(&token::Question) { // `expr?` - e = self.mk_expr(lo.to(self.prev_span), ExprKind::Try(e), AttrVec::new()); + e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e), AttrVec::new()); continue; } if self.eat(&token::Dot) { @@ -710,7 +762,7 @@ impl<'a> Parser<'a> { } fn parse_dot_suffix_expr(&mut self, lo: Span, base: P) -> PResult<'a, P> { - match self.token.kind { + match self.token.uninterpolate().kind { token::Ident(..) => self.parse_dot_suffix(base, lo), token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => { Ok(self.parse_tuple_field_access_expr(lo, base, symbol, suffix)) @@ -742,8 +794,8 @@ impl<'a> Parser<'a> { let fstr = sym.as_str(); let msg = format!("unexpected token: `{}`", sym); - let mut err = self.struct_span_err(self.prev_span, &msg); - err.span_label(self.prev_span, "unexpected token"); + let mut err = self.struct_span_err(self.prev_token.span, &msg); + err.span_label(self.prev_token.span, "unexpected token"); if fstr.chars().all(|x| "0123456789.".contains(x)) { let float = match fstr.parse::() { @@ -760,10 +812,10 @@ impl<'a> Parser<'a> { s.print_usize(float.trunc() as usize); s.pclose(); s.s.word("."); - s.s.word(fstr.splitn(2, ".").last().unwrap().to_string()) + s.s.word(fstr.splitn(2, '.').last().unwrap().to_string()) }); err.span_suggestion( - lo.to(self.prev_span), + lo.to(self.prev_token.span), "try parenthesizing the first index", sugg, Applicability::MachineApplicable, @@ -779,8 +831,8 @@ impl<'a> Parser<'a> { field: Symbol, suffix: Option, ) -> P { - let span = self.token.span; self.bump(); + let span = self.prev_token.span; let field = ExprKind::Field(base, Ident::new(field, span)); self.expect_no_suffix(span, "a tuple index", suffix); self.mk_expr(lo.to(span), field, AttrVec::new()) @@ -789,7 +841,7 @@ impl<'a> Parser<'a> { /// Parse a function call expression, `expr(...)`. fn parse_fn_call_expr(&mut self, lo: Span, fun: P) -> P { let seq = self.parse_paren_expr_seq().map(|args| { - self.mk_expr(lo.to(self.prev_span), self.mk_call(fun, args), AttrVec::new()) + self.mk_expr(lo.to(self.prev_token.span), self.mk_call(fun, args), AttrVec::new()) }); self.recover_seq_parse_error(token::Paren, lo, seq) } @@ -799,12 +851,12 @@ impl<'a> Parser<'a> { self.bump(); // `[` let index = self.parse_expr()?; self.expect(&token::CloseDelim(token::Bracket))?; - Ok(self.mk_expr(lo.to(self.prev_span), self.mk_index(base, index), AttrVec::new())) + Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index), AttrVec::new())) } /// Assuming we have just parsed `.`, continue parsing into an expression. fn parse_dot_suffix(&mut self, self_arg: P, lo: Span) -> PResult<'a, P> { - if self.token.span.rust_2018() && self.eat_keyword(kw::Await) { + if self.token.uninterpolated_span().rust_2018() && self.eat_keyword(kw::Await) { return self.mk_await_expr(self_arg, lo); } @@ -816,7 +868,7 @@ impl<'a> Parser<'a> { let mut args = self.parse_paren_expr_seq()?; args.insert(0, self_arg); - let span = lo.to(self.prev_span); + let span = lo.to(self.prev_token.span); Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args), AttrVec::new())) } else { // Field access `expr.f` @@ -828,7 +880,7 @@ impl<'a> Parser<'a> { .emit(); } - let span = lo.to(self.prev_span); + let span = lo.to(self.prev_token.span); Ok(self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), AttrVec::new())) } } @@ -867,25 +919,25 @@ impl<'a> Parser<'a> { } else if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs)) - } else if self.token.is_path_start() { + } else if self.check_path() { self.parse_path_start_expr(attrs) } else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { self.parse_closure_expr(attrs) } else if self.eat_keyword(kw::If) { self.parse_if_expr(attrs) } else if self.eat_keyword(kw::For) { - self.parse_for_expr(None, self.prev_span, attrs) + self.parse_for_expr(None, self.prev_token.span, attrs) } else if self.eat_keyword(kw::While) { - self.parse_while_expr(None, self.prev_span, attrs) + self.parse_while_expr(None, self.prev_token.span, attrs) } else if let Some(label) = self.eat_label() { self.parse_labeled_expr(label, attrs) } else if self.eat_keyword(kw::Loop) { - self.parse_loop_expr(None, self.prev_span, attrs) + self.parse_loop_expr(None, self.prev_token.span, attrs) } else if self.eat_keyword(kw::Continue) { let kind = ExprKind::Continue(self.eat_label()); - Ok(self.mk_expr(lo.to(self.prev_span), kind, attrs)) + Ok(self.mk_expr(lo.to(self.prev_token.span), kind, attrs)) } else if self.eat_keyword(kw::Match) { - let match_sp = self.prev_span; + let match_sp = self.prev_token.span; self.parse_match_expr(attrs).map_err(|mut err| { err.span_label(match_sp, "while parsing this match expression"); err @@ -918,7 +970,7 @@ impl<'a> Parser<'a> { // | ^ expected expression self.bump(); Ok(self.mk_expr_err(self.token.span)) - } else if self.token.span.rust_2018() { + } else if self.token.uninterpolated_span().rust_2018() { // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly. if self.check_keyword(kw::Async) { if self.is_async_block() { @@ -928,7 +980,7 @@ impl<'a> Parser<'a> { self.parse_closure_expr(attrs) } } else if self.eat_keyword(kw::Await) { - self.recover_incorrect_await_syntax(lo, self.prev_span, attrs) + self.recover_incorrect_await_syntax(lo, self.prev_token.span, attrs) } else { self.parse_lit_expr(attrs) } @@ -941,7 +993,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; match self.parse_opt_lit() { Some(literal) => { - let expr = self.mk_expr(lo.to(self.prev_span), ExprKind::Lit(literal), attrs); + let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs); self.maybe_recover_from_bad_qpath(expr, true) } None => return Err(self.expected_expression_found()), @@ -962,12 +1014,12 @@ impl<'a> Parser<'a> { }; let kind = if es.len() == 1 && !trailing_comma { // `(e)` is parenthesized `e`. - ExprKind::Paren(es.into_iter().nth(0).unwrap()) + ExprKind::Paren(es.into_iter().next().unwrap()) } else { // `(e,)` is a tuple with only one field, `e`. ExprKind::Tup(es) }; - let expr = self.mk_expr(lo.to(self.prev_span), kind, attrs); + let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); self.maybe_recover_from_bad_qpath(expr, true) } @@ -1002,7 +1054,7 @@ impl<'a> Parser<'a> { ExprKind::Array(vec![first_expr]) } }; - let expr = self.mk_expr(lo.to(self.prev_span), kind, attrs); + let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); self.maybe_recover_from_bad_qpath(expr, true) } @@ -1013,12 +1065,12 @@ impl<'a> Parser<'a> { // `!`, as an operator, is prefix, so we know this isn't that. let (hi, kind) = if self.eat(&token::Not) { // MACRO INVOCATION expression - let mac = Mac { + let mac = MacCall { path, args: self.parse_mac_args()?, prior_type_ascription: self.last_type_ascription, }; - (self.prev_span, ExprKind::Mac(mac)) + (self.prev_token.span, ExprKind::MacCall(mac)) } else if self.check(&token::OpenDelim(token::Brace)) { if let Some(expr) = self.maybe_parse_struct_expr(lo, &path, &attrs) { return expr; @@ -1033,26 +1085,44 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + /// Parse `'label: $expr`. The label is already parsed. fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P> { let lo = label.ident.span; - self.expect(&token::Colon)?; - if self.eat_keyword(kw::While) { - return self.parse_while_expr(Some(label), lo, attrs); - } - if self.eat_keyword(kw::For) { - return self.parse_for_expr(Some(label), lo, attrs); - } - if self.eat_keyword(kw::Loop) { - return self.parse_loop_expr(Some(label), lo, attrs); - } - if self.token == token::OpenDelim(token::Brace) { - return self.parse_block_expr(Some(label), lo, BlockCheckMode::Default, attrs); + let label = Some(label); + let ate_colon = self.eat(&token::Colon); + let expr = if self.eat_keyword(kw::While) { + self.parse_while_expr(label, lo, attrs) + } else if self.eat_keyword(kw::For) { + self.parse_for_expr(label, lo, attrs) + } else if self.eat_keyword(kw::Loop) { + self.parse_loop_expr(label, lo, attrs) + } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() { + self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs) + } else { + let msg = "expected `while`, `for`, `loop` or `{` after a label"; + self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit(); + // Continue as an expression in an effort to recover on `'label: non_block_expr`. + self.parse_expr() + }?; + + if !ate_colon { + self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span); } - let msg = "expected `while`, `for`, `loop` or `{` after a label"; - self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit(); - // Continue as an expression in an effort to recover on `'label: non_block_expr`. - self.parse_expr() + Ok(expr) + } + + fn error_labeled_expr_must_be_followed_by_colon(&self, lo: Span, span: Span) { + self.struct_span_err(span, "labeled expression must be followed by `:`") + .span_label(lo, "the label") + .span_suggestion_short( + lo.shrink_to_hi(), + "add `:` after the label", + ": ".to_string(), + Applicability::MachineApplicable, + ) + .note("labels are used before loops and blocks, allowing e.g., `break 'label` to them") + .emit(); } /// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead. @@ -1062,7 +1132,7 @@ impl<'a> Parser<'a> { self.bump(); // `do` self.bump(); // `catch` - let span_dc = lo.to(self.prev_span); + let span_dc = lo.to(self.prev_token.span); self.struct_span_err(span_dc, "found removed `do catch` syntax") .span_suggestion( span_dc, @@ -1083,15 +1153,15 @@ impl<'a> Parser<'a> { /// Parse `"return" expr?`. fn parse_return_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { - let lo = self.prev_span; + let lo = self.prev_token.span; let kind = ExprKind::Ret(self.parse_expr_opt()?); - let expr = self.mk_expr(lo.to(self.prev_span), kind, attrs); + let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); self.maybe_recover_from_bad_qpath(expr, true) } /// Parse `"('label ":")? break expr?`. fn parse_break_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { - let lo = self.prev_span; + let lo = self.prev_token.span; let label = self.eat_label(); let kind = if self.token != token::OpenDelim(token::Brace) || !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) @@ -1100,15 +1170,15 @@ impl<'a> Parser<'a> { } else { None }; - let expr = self.mk_expr(lo.to(self.prev_span), ExprKind::Break(label, kind), attrs); + let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind), attrs); self.maybe_recover_from_bad_qpath(expr, true) } /// Parse `"yield" expr?`. fn parse_yield_expr(&mut self, attrs: AttrVec) -> PResult<'a, P> { - let lo = self.prev_span; + let lo = self.prev_token.span; let kind = ExprKind::Yield(self.parse_expr_opt()?); - let span = lo.to(self.prev_span); + let span = lo.to(self.prev_token.span); self.sess.gated_spans.gate(sym::generators, span); let expr = self.mk_expr(span, kind, attrs); self.maybe_recover_from_bad_qpath(expr, true) @@ -1313,7 +1383,11 @@ impl<'a> Parser<'a> { let expr = self.mk_expr(lit.span, ExprKind::Lit(lit), AttrVec::new()); if minus_present { - Ok(self.mk_expr(lo.to(self.prev_span), self.mk_unary(UnOp::Neg, expr), AttrVec::new())) + Ok(self.mk_expr( + lo.to(self.prev_token.span), + self.mk_unary(UnOp::Neg, expr), + AttrVec::new(), + )) } else { Ok(expr) } @@ -1325,18 +1399,20 @@ impl<'a> Parser<'a> { opt_label: Option()` - Generic, - - /// the method's receiver (`self` argument) can't be dispatched on - UndispatchableReceiver, -} +pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation}; /// Returns the object safety violations that affect /// astconv -- currently, `Self` in supertraits. This is needed @@ -175,10 +47,7 @@ pub fn astconv_object_safety_violations( violations } -pub fn object_safety_violations( - tcx: TyCtxt<'_>, - trait_def_id: DefId, -) -> Vec { +fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Vec { debug_assert!(tcx.generics_of(trait_def_id).has_self); debug!("object_safety_violations: {:?}", trait_def_id); @@ -212,7 +81,7 @@ fn object_safety_violations_for_trait( // Check methods for violations. let mut violations: Vec<_> = tcx .associated_items(trait_def_id) - .iter() + .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Method) .filter_map(|item| { object_safety_violation_for_method(tcx, trait_def_id, &item) @@ -288,7 +157,7 @@ fn object_safety_violations_for_trait( violations.extend( tcx.associated_items(trait_def_id) - .iter() + .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Const) .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)), ); @@ -316,7 +185,7 @@ fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> .filter_map(|pred| { match pred { hir::WherePredicate::BoundPredicate(pred) - if pred.bounded_ty.hir_id.owner_def_id() == trait_def_id => + if pred.bounded_ty.hir_id.owner.to_def_id() == trait_def_id => { // Fetch spans for trait bounds that are Sized: // `trait T where Self: Pred` @@ -552,7 +421,7 @@ fn virtual_call_violation_for_method<'tcx>( } else { // Do sanity check to make sure the receiver actually has the layout of a pointer. - use crate::ty::layout::Abi; + use rustc::ty::layout::Abi; let param_env = tcx.param_env(method.def_id); @@ -645,7 +514,7 @@ fn object_ty_for_trait<'tcx>( let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) .flat_map(|super_trait_ref| { tcx.associated_items(super_trait_ref.def_id()) - .iter() + .in_definition_order() .map(move |item| (super_trait_ref, item)) }) .filter(|(_, item)| item.kind == ty::AssocKind::Type) @@ -744,7 +613,7 @@ fn receiver_is_dispatchable<'tcx>( }; // the type `U` in the query - // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now. + // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now. // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can // replace this with `dyn Trait` let unsized_self_ty: Ty<'tcx> = @@ -904,6 +773,6 @@ fn contains_illegal_self_type_reference<'tcx>( error } -pub(super) fn is_object_safe_provider(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { - object_safety_violations(tcx, trait_def_id).is_empty() +pub fn provide(providers: &mut ty::query::Providers<'_>) { + *providers = ty::query::Providers { object_safety_violations, ..*providers }; } diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc_trait_selection/traits/on_unimplemented.rs similarity index 97% rename from src/librustc/traits/on_unimplemented.rs rename to src/librustc_trait_selection/traits/on_unimplemented.rs index ca824d40e38..19260293ee6 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc_trait_selection/traits/on_unimplemented.rs @@ -1,15 +1,15 @@ use fmt_macros::{Parser, Piece, Position}; -use crate::ty::{self, GenericParamDefKind, TyCtxt}; -use crate::util::common::ErrorReported; +use rustc::ty::{self, GenericParamDefKind, TyCtxt}; +use rustc::util::common::ErrorReported; +use rustc_ast::ast::{MetaItem, NestedMetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; use rustc_errors::struct_span_err; use rustc_hir::def_id::DefId; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use syntax::ast::{MetaItem, NestedMetaItem}; #[derive(Clone, Debug)] pub struct OnUnimplementedFormatString(Symbol); @@ -237,10 +237,8 @@ impl<'tcx> OnUnimplementedDirective { } } - let options: FxHashMap = options - .into_iter() - .filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))) - .collect(); + let options: FxHashMap = + options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect(); OnUnimplementedNote { label: label.map(|l| l.format(tcx, trait_ref, &options)), message: message.map(|m| m.format(tcx, trait_ref, &options)), diff --git a/src/librustc/traits/project.rs b/src/librustc_trait_selection/traits/project.rs similarity index 85% rename from src/librustc/traits/project.rs rename to src/librustc_trait_selection/traits/project.rs index 5d9f4ddfd16..1ad91574212 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -4,24 +4,27 @@ use super::elaborate_predicates; use super::specialization_graph; use super::translate_substs; use super::util; +use super::MismatchedProjectionTypes; use super::Obligation; use super::ObligationCause; use super::PredicateObligation; use super::Selection; use super::SelectionContext; use super::SelectionError; +use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; -use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; -use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; +use crate::traits::error_reporting::InferCtxtExt; +use rustc::ty::fold::{TypeFoldable, TypeFolder}; +use rustc::ty::subst::{InternalSubsts, Subst}; +use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_ast::ast::Ident; +use rustc_errors::ErrorReported; use rustc_hir::def_id::DefId; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; -use syntax::ast::Ident; pub use rustc::traits::Reveal; @@ -41,11 +44,6 @@ pub enum ProjectionTyError<'tcx> { TraitSelectionError(SelectionError<'tcx>), } -#[derive(Clone)] -pub struct MismatchedProjectionTypes<'tcx> { - pub err: ty::error::TypeError<'tcx>, -} - #[derive(PartialEq, Eq, Debug)] enum ProjectionTyCandidate<'tcx> { // from a where-clause in the env or object type @@ -393,20 +391,6 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } } -#[derive(Clone, TypeFoldable)] -pub struct Normalized<'tcx, T> { - pub value: T, - pub obligations: Vec>, -} - -pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>; - -impl<'tcx, T> Normalized<'tcx, T> { - pub fn with(self, value: U) -> Normalized<'tcx, U> { - Normalized { value: value, obligations: self.obligations } - } -} - /// The guts of `normalize`: normalize a specific projection like `::Item`. The result is always a type (and possibly /// additional obligations). If ambiguity arises, which implies that @@ -469,7 +453,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let infcx = selcx.infcx(); let projection_ty = infcx.resolve_vars_if_possible(&projection_ty); - let cache_key = ProjectionCacheKey { ty: projection_ty }; + let cache_key = ProjectionCacheKey::new(projection_ty); debug!( "opt_normalize_projection_type(\ @@ -490,22 +474,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( match cache_result { Ok(()) => {} Err(ProjectionCacheEntry::Ambiguous) => { - // If we found ambiguity the last time, that generally - // means we will continue to do so until some type in the - // key changes (and we know it hasn't, because we just - // fully resolved it). One exception though is closure - // types, which can transition from having a fixed kind to - // no kind with no visible change in the key. - // - // FIXME(#32286) refactor this so that closure type - // changes + // If we found ambiguity the last time, that means we will continue + // to do so until some type in the key changes (and we know it + // hasn't, because we just fully resolved it). debug!( "opt_normalize_projection_type: \ found cache entry: ambiguous" ); - if !projection_ty.has_closure_types() { - return None; - } + return None; } Err(ProjectionCacheEntry::InProgress) => { // If while normalized A::B, we are asked to normalize @@ -1035,7 +1011,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // NOTE: This should be kept in sync with the similar code in // `rustc::ty::instance::resolve_associated_item()`. let node_item = - assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id); + assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id) + .map_err(|ErrorReported| ())?; let is_default = if node_item.node.is_from_trait() { // If true, the impl inherited a `type Foo = Bar` @@ -1054,25 +1031,40 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // an error when we confirm the candidate // (which will ultimately lead to `normalize_to_error` // being invoked). - node_item.item.defaultness.has_value() + false } else { + // If we're looking at a trait *impl*, the item is + // specializable if the impl or the item are marked + // `default`. node_item.item.defaultness.is_default() || super::util::impl_is_default(selcx.tcx(), node_item.node.def_id()) }; - // Only reveal a specializable default if we're past type-checking - // and the obligations is monomorphic, otherwise passes such as - // transmute checking and polymorphic MIR optimizations could - // get a result which isn't correct for all monomorphizations. - if !is_default { - true - } else if obligation.param_env.reveal == Reveal::All { - // NOTE(eddyb) inference variables can resolve to parameters, so - // assume `poly_trait_ref` isn't monomorphic, if it contains any. - let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(&poly_trait_ref); - !poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst() - } else { - false + match is_default { + // Non-specializable items are always projectable + false => true, + + // Only reveal a specializable default if we're past type-checking + // and the obligation is monomorphic, otherwise passes such as + // transmute checking and polymorphic MIR optimizations could + // get a result which isn't correct for all monomorphizations. + true if obligation.param_env.reveal == Reveal::All => { + // NOTE(eddyb) inference variables can resolve to parameters, so + // assume `poly_trait_ref` isn't monomorphic, if it contains any. + let poly_trait_ref = + selcx.infcx().resolve_vars_if_possible(&poly_trait_ref); + !poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst() + } + + true => { + debug!( + "assemble_candidates_from_impls: not eligible due to default: \ + assoc_ty={} predicate={}", + selcx.tcx().def_path_str(node_item.item.def_id), + obligation.predicate, + ); + false + } } } super::VtableParam(..) => { @@ -1284,7 +1276,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( substs: trait_ref.substs, item_def_id: obligation.predicate.item_def_id, }, - ty: ty, + ty, } }); @@ -1415,7 +1407,10 @@ fn confirm_impl_candidate<'cx, 'tcx>( let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); let param_env = obligation.param_env; - let assoc_ty = assoc_ty_def(selcx, impl_def_id, assoc_item_id); + let assoc_ty = match assoc_ty_def(selcx, impl_def_id, assoc_item_id) { + Ok(assoc_ty) => assoc_ty, + Err(ErrorReported) => return Progress { ty: tcx.types.err, obligations: nested }, + }; if !assoc_ty.item.defaultness.has_value() { // This means that the impl is missing a definition for the @@ -1454,14 +1449,14 @@ fn assoc_ty_def( selcx: &SelectionContext<'_, '_>, impl_def_id: DefId, assoc_ty_def_id: DefId, -) -> specialization_graph::NodeItem { +) -> Result, ErrorReported> { let tcx = selcx.tcx(); let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident; let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id; let trait_def = tcx.trait_def(trait_def_id); // This function may be called while we are still building the - // specialization graph that is queried below (via TraidDef::ancestors()), + // specialization graph that is queried below (via TraitDef::ancestors()), // so, in order to avoid unnecessary infinite recursion, we manually look // for the associated item at the given impl. // If there is no such item in that impl, this function will fail with a @@ -1471,17 +1466,16 @@ fn assoc_ty_def( if matches!(item.kind, ty::AssocKind::Type | ty::AssocKind::OpaqueTy) && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id) { - return specialization_graph::NodeItem { + return Ok(specialization_graph::NodeItem { node: specialization_graph::Node::Impl(impl_def_id), item: *item, - }; + }); } } - if let Some(assoc_item) = - trait_def.ancestors(tcx, impl_def_id).leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) - { - assoc_item + let ancestors = trait_def.ancestors(tcx, impl_def_id)?; + if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) { + Ok(assoc_item) } else { // This is saying that neither the trait nor // the impl contain a definition for this @@ -1493,177 +1487,29 @@ fn assoc_ty_def( } } -// # Cache - -/// The projection cache. Unlike the standard caches, this can include -/// infcx-dependent type variables, therefore we have to roll the -/// cache back each time we roll a snapshot back, to avoid assumptions -/// on yet-unresolved inference variables. Types with placeholder -/// regions also have to be removed when the respective snapshot ends. -/// -/// Because of that, projection cache entries can be "stranded" and left -/// inaccessible when type variables inside the key are resolved. We make no -/// attempt to recover or remove "stranded" entries, but rather let them be -/// (for the lifetime of the infcx). -/// -/// Entries in the projection cache might contain inference variables -/// that will be resolved by obligations on the projection cache entry (e.g., -/// when a type parameter in the associated type is constrained through -/// an "RFC 447" projection on the impl). -/// -/// When working with a fulfillment context, the derived obligations of each -/// projection cache entry will be registered on the fulfillcx, so any users -/// that can wait for a fulfillcx fixed point need not care about this. However, -/// users that don't wait for a fixed point (e.g., trait evaluation) have to -/// resolve the obligations themselves to make sure the projected result is -/// ok and avoid issues like #43132. -/// -/// If that is done, after evaluation the obligations, it is a good idea to -/// call `ProjectionCache::complete` to make sure the obligations won't be -/// re-evaluated and avoid an exponential worst-case. -// -// FIXME: we probably also want some sort of cross-infcx cache here to -// reduce the amount of duplication. Let's see what we get with the Chalk reforms. -#[derive(Default)] -pub struct ProjectionCache<'tcx> { - map: SnapshotMap, ProjectionCacheEntry<'tcx>>, -} - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub struct ProjectionCacheKey<'tcx> { - ty: ty::ProjectionTy<'tcx>, +crate trait ProjectionCacheKeyExt<'tcx>: Sized { + fn from_poly_projection_predicate( + selcx: &mut SelectionContext<'cx, 'tcx>, + predicate: &ty::PolyProjectionPredicate<'tcx>, + ) -> Option; } -impl<'cx, 'tcx> ProjectionCacheKey<'tcx> { - pub fn from_poly_projection_predicate( +impl<'tcx> ProjectionCacheKeyExt<'tcx> for ProjectionCacheKey<'tcx> { + fn from_poly_projection_predicate( selcx: &mut SelectionContext<'cx, 'tcx>, predicate: &ty::PolyProjectionPredicate<'tcx>, ) -> Option { let infcx = selcx.infcx(); // We don't do cross-snapshot caching of obligations with escaping regions, // so there's no cache key to use - predicate.no_bound_vars().map(|predicate| ProjectionCacheKey { - // We don't attempt to match up with a specific type-variable state - // from a specific call to `opt_normalize_projection_type` - if - // there's no precise match, the original cache entry is "stranded" - // anyway. - ty: infcx.resolve_vars_if_possible(&predicate.projection_ty), + predicate.no_bound_vars().map(|predicate| { + ProjectionCacheKey::new( + // We don't attempt to match up with a specific type-variable state + // from a specific call to `opt_normalize_projection_type` - if + // there's no precise match, the original cache entry is "stranded" + // anyway. + infcx.resolve_vars_if_possible(&predicate.projection_ty), + ) }) } } - -#[derive(Clone, Debug)] -enum ProjectionCacheEntry<'tcx> { - InProgress, - Ambiguous, - Error, - NormalizedTy(NormalizedTy<'tcx>), -} - -// N.B., intentionally not Clone -pub struct ProjectionCacheSnapshot { - snapshot: Snapshot, -} - -impl<'tcx> ProjectionCache<'tcx> { - pub fn clear(&mut self) { - self.map.clear(); - } - - pub fn snapshot(&mut self) -> ProjectionCacheSnapshot { - ProjectionCacheSnapshot { snapshot: self.map.snapshot() } - } - - pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.rollback_to(snapshot.snapshot); - } - - pub fn rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) { - self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders()); - } - - pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.commit(snapshot.snapshot); - } - - /// Try to start normalize `key`; returns an error if - /// normalization already occurred (this error corresponds to a - /// cache hit, so it's actually a good thing). - fn try_start( - &mut self, - key: ProjectionCacheKey<'tcx>, - ) -> Result<(), ProjectionCacheEntry<'tcx>> { - if let Some(entry) = self.map.get(&key) { - return Err(entry.clone()); - } - - self.map.insert(key, ProjectionCacheEntry::InProgress); - Ok(()) - } - - /// Indicates that `key` was normalized to `value`. - fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) { - debug!( - "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", - key, value - ); - let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value)); - assert!(!fresh_key, "never started projecting `{:?}`", key); - } - - /// Mark the relevant projection cache key as having its derived obligations - /// complete, so they won't have to be re-computed (this is OK to do in a - /// snapshot - if the snapshot is rolled back, the obligations will be - /// marked as incomplete again). - pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) { - let ty = match self.map.get(&key) { - Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => { - debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); - ty.value - } - ref value => { - // Type inference could "strand behind" old cache entries. Leave - // them alone for now. - debug!("ProjectionCacheEntry::complete({:?}) - ignoring {:?}", key, value); - return; - } - }; - - self.map.insert( - key, - ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }), - ); - } - - /// A specialized version of `complete` for when the key's value is known - /// to be a NormalizedTy. - pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) { - // We want to insert `ty` with no obligations. If the existing value - // already has no obligations (as is common) we don't insert anything. - if !ty.obligations.is_empty() { - self.map.insert( - key, - ProjectionCacheEntry::NormalizedTy(Normalized { - value: ty.value, - obligations: vec![], - }), - ); - } - } - - /// Indicates that trying to normalize `key` resulted in - /// ambiguity. No point in trying it again then until we gain more - /// type information (in which case, the "fully resolved" key will - /// be different). - fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) { - let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous); - assert!(!fresh, "never started projecting `{:?}`", key); - } - - /// Indicates that trying to normalize `key` resulted in - /// error. - fn error(&mut self, key: ProjectionCacheKey<'tcx>) { - let fresh = self.map.insert(key, ProjectionCacheEntry::Error); - assert!(!fresh, "never started projecting `{:?}`", key); - } -} diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc_trait_selection/traits/query/dropck_outlives.rs similarity index 95% rename from src/librustc/traits/query/dropck_outlives.rs rename to src/librustc_trait_selection/traits/query/dropck_outlives.rs index a1d7a2836e4..40a21b5a6ed 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc_trait_selection/traits/query/dropck_outlives.rs @@ -7,7 +7,11 @@ use rustc::ty::{self, Ty, TyCtxt}; pub use rustc::traits::query::{DropckOutlivesResult, DtorckConstraint}; -impl<'cx, 'tcx> At<'cx, 'tcx> { +pub trait AtExt<'tcx> { + fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec>>; +} + +impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { /// Given a type `ty` of some value being dropped, computes a set /// of "kinds" (types, regions) that must be outlive the execution /// of the destructor. These basically correspond to data that the @@ -25,7 +29,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { /// /// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md /// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md - pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec>> { + fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec>> { debug!("dropck_outlives(ty={:?}, param_env={:?})", ty, self.param_env,); // Quick check: there are a number of cases that we know do not require diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc_trait_selection/traits/query/evaluate_obligation.rs similarity index 71% rename from src/librustc/traits/query/evaluate_obligation.rs rename to src/librustc_trait_selection/traits/query/evaluate_obligation.rs index b9ce3ccff27..0569f6217da 100644 --- a/src/librustc/traits/query/evaluate_obligation.rs +++ b/src/librustc_trait_selection/traits/query/evaluate_obligation.rs @@ -4,10 +4,35 @@ use crate::traits::{ EvaluationResult, OverflowError, PredicateObligation, SelectionContext, TraitQueryMode, }; -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { +pub trait InferCtxtExt<'tcx> { + fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool; + + fn predicate_must_hold_considering_regions( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> bool; + + fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool; + + fn evaluate_obligation( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> Result; + + // Helper function that canonicalizes and runs the query. If an + // overflow results, we re-run it in the local context so we can + // report a nice error. + /*crate*/ + fn evaluate_obligation_no_overflow( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> EvaluationResult; +} + +impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { /// Evaluates whether the predicate can be satisfied (by any means) /// in the given `ParamEnv`. - pub fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { + fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { self.evaluate_obligation_no_overflow(obligation).may_apply() } @@ -17,7 +42,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// /// This version may conservatively fail when outlives obligations /// are required. - pub fn predicate_must_hold_considering_regions( + fn predicate_must_hold_considering_regions( &self, obligation: &PredicateObligation<'tcx>, ) -> bool { @@ -29,15 +54,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// not entirely accurate if inference variables are involved. /// /// This version ignores all outlives constraints. - pub fn predicate_must_hold_modulo_regions( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> bool { + fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool { self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions() } /// Evaluate a given predicate, capturing overflow and propagating it back. - pub fn evaluate_obligation( + fn evaluate_obligation( &self, obligation: &PredicateObligation<'tcx>, ) -> Result { @@ -53,7 +75,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // Helper function that canonicalizes and runs the query. If an // overflow results, we re-run it in the local context so we can // report a nice error. - crate fn evaluate_obligation_no_overflow( + fn evaluate_obligation_no_overflow( &self, obligation: &PredicateObligation<'tcx>, ) -> EvaluationResult { diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc_trait_selection/traits/query/method_autoderef.rs similarity index 100% rename from src/librustc/traits/query/method_autoderef.rs rename to src/librustc_trait_selection/traits/query/method_autoderef.rs diff --git a/src/librustc/traits/query/mod.rs b/src/librustc_trait_selection/traits/query/mod.rs similarity index 92% rename from src/librustc/traits/query/mod.rs rename to src/librustc_trait_selection/traits/query/mod.rs index 20a873dc4c6..77b5ec669a0 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc_trait_selection/traits/query/mod.rs @@ -12,4 +12,4 @@ pub mod normalize; pub mod outlives_bounds; pub mod type_op; -pub use rustc::traits::types::query::*; +pub use rustc::traits::query::*; diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs similarity index 93% rename from src/librustc/traits/query/normalize.rs rename to src/librustc_trait_selection/traits/query/normalize.rs index 737b4fc6bb9..adec2ddb253 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc_trait_selection/traits/query/normalize.rs @@ -5,17 +5,24 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; -use crate::traits::project::Normalized; +use crate::traits::error_reporting::InferCtxtExt; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; -use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::subst::Subst; -use crate::ty::{self, Ty, TyCtxt}; +use rustc::ty::fold::{TypeFoldable, TypeFolder}; +use rustc::ty::subst::Subst; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc_infer::traits::Normalized; use super::NoSolution; pub use rustc::traits::query::NormalizationResult; -impl<'cx, 'tcx> At<'cx, 'tcx> { +pub trait AtExt<'tcx> { + fn normalize(&self, value: &T) -> Result, NoSolution> + where + T: TypeFoldable<'tcx>; +} + +impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { /// Normalize `value` in the context of the inference context, /// yielding a resulting type, or an error if `value` cannot be /// normalized. If you don't care about regions, you should prefer @@ -29,7 +36,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { /// normalizing, but for now should be used only when we actually /// know that normalization will succeed, since error reporting /// and other details are still "under development". - pub fn normalize(&self, value: &T) -> Result, NoSolution> + fn normalize(&self, value: &T) -> Result, NoSolution> where T: TypeFoldable<'tcx>, { diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc_trait_selection/traits/query/outlives_bounds.rs similarity index 77% rename from src/librustc/traits/query/outlives_bounds.rs rename to src/librustc_trait_selection/traits/query/outlives_bounds.rs index 594faffa5f3..05c96dd520a 100644 --- a/src/librustc/traits/query/outlives_bounds.rs +++ b/src/librustc_trait_selection/traits/query/outlives_bounds.rs @@ -1,14 +1,25 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::InferCtxt; use crate::traits::query::NoSolution; -use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt}; -use crate::ty::{self, Ty}; +use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine}; +use rustc::ty::{self, Ty}; use rustc_hir as hir; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::Span; pub use rustc::traits::query::OutlivesBound; -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { +pub trait InferCtxtExt<'tcx> { + fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ty: Ty<'tcx>, + span: Span, + ) -> Vec>; +} + +impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { /// Implied bounds are region relationships that we deduce /// automatically. The idea is that (e.g.) a caller must check that a /// function's argument types are well-formed immediately before @@ -30,7 +41,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// - `ty`, the type that we are supposed to assume is WF. /// - `span`, a span to use when normalizing, hopefully not important, /// might be useful if a `bug!` occurs. - pub fn implied_outlives_bounds( + fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, @@ -82,22 +93,3 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { result.value } } - -pub fn explicit_outlives_bounds<'tcx>( - param_env: ty::ParamEnv<'tcx>, -) -> impl Iterator> + 'tcx { - debug!("explicit_outlives_bounds()"); - param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate { - ty::Predicate::Projection(..) - | ty::Predicate::Trait(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => None, - ty::Predicate::RegionOutlives(ref data) => data - .no_bound_vars() - .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), - }) -} diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc_trait_selection/traits/query/type_op/ascribe_user_type.rs similarity index 100% rename from src/librustc/traits/query/type_op/ascribe_user_type.rs rename to src/librustc_trait_selection/traits/query/type_op/ascribe_user_type.rs diff --git a/src/librustc/traits/query/type_op/custom.rs b/src/librustc_trait_selection/traits/query/type_op/custom.rs similarity index 96% rename from src/librustc/traits/query/type_op/custom.rs rename to src/librustc_trait_selection/traits/query/type_op/custom.rs index c1c9030b888..915e8ae4a7a 100644 --- a/src/librustc/traits/query/type_op/custom.rs +++ b/src/librustc_trait_selection/traits/query/type_op/custom.rs @@ -4,7 +4,9 @@ use std::fmt; use crate::infer::canonical::query_response; use crate::infer::canonical::QueryRegionConstraints; -use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt}; +use crate::traits::engine::TraitEngineExt as _; +use crate::traits::{ObligationCause, TraitEngine}; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::DUMMY_SP; use std::rc::Rc; diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc_trait_selection/traits/query/type_op/eq.rs similarity index 94% rename from src/librustc/traits/query/type_op/eq.rs rename to src/librustc_trait_selection/traits/query/type_op/eq.rs index 1de13430d46..3b6fbc7d8dd 100644 --- a/src/librustc/traits/query/type_op/eq.rs +++ b/src/librustc_trait_selection/traits/query/type_op/eq.rs @@ -1,6 +1,6 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, TyCtxt}; +use rustc::ty::{ParamEnvAnd, TyCtxt}; pub use rustc::traits::query::type_op::Eq; diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc_trait_selection/traits/query/type_op/implied_outlives_bounds.rs similarity index 96% rename from src/librustc/traits/query/type_op/implied_outlives_bounds.rs rename to src/librustc_trait_selection/traits/query/type_op/implied_outlives_bounds.rs index 6f45d76a8e9..3dad546872e 100644 --- a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs +++ b/src/librustc_trait_selection/traits/query/type_op/implied_outlives_bounds.rs @@ -1,7 +1,7 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::outlives_bounds::OutlivesBound; use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; +use rustc::ty::{ParamEnvAnd, Ty, TyCtxt}; #[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] pub struct ImpliedOutlivesBounds<'tcx> { diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc_trait_selection/traits/query/type_op/mod.rs similarity index 96% rename from src/librustc/traits/query/type_op/mod.rs rename to src/librustc_trait_selection/traits/query/type_op/mod.rs index 2d03d77cf66..1644746c16e 100644 --- a/src/librustc/traits/query/type_op/mod.rs +++ b/src/librustc_trait_selection/traits/query/type_op/mod.rs @@ -4,8 +4,8 @@ use crate::infer::canonical::{ use crate::infer::{InferCtxt, InferOk}; use crate::traits::query::Fallible; use crate::traits::ObligationCause; -use crate::ty::fold::TypeFoldable; -use crate::ty::{ParamEnvAnd, TyCtxt}; +use rustc::ty::fold::TypeFoldable; +use rustc::ty::{ParamEnvAnd, TyCtxt}; use std::fmt; use std::rc::Rc; @@ -19,7 +19,7 @@ pub mod prove_predicate; use self::prove_predicate::ProvePredicate; pub mod subtype; -pub use crate::traits::types::query::type_op::*; +pub use rustc::traits::query::type_op::*; /// "Type ops" are used in NLL to perform some particular action and /// extract out the resulting region constraints (or an error if it @@ -44,7 +44,7 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug { /// first canonicalize the key and then invoke the query on the tcx, /// which produces the resulting query region constraints. /// -/// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html +/// [c]: https://rustc-dev-guide.rust-lang.org/traits/canonicalization.html pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx { type QueryResponse: TypeFoldable<'tcx>; diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc_trait_selection/traits/query/type_op/normalize.rs similarity index 96% rename from src/librustc/traits/query/type_op/normalize.rs rename to src/librustc_trait_selection/traits/query/type_op/normalize.rs index b1e0e29620d..d2eec53bf80 100644 --- a/src/librustc/traits/query/type_op/normalize.rs +++ b/src/librustc_trait_selection/traits/query/type_op/normalize.rs @@ -1,7 +1,7 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; -use crate::ty::fold::TypeFoldable; -use crate::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt}; +use rustc::ty::fold::TypeFoldable; +use rustc::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt}; use std::fmt; pub use rustc::traits::query::type_op::Normalize; diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc_trait_selection/traits/query/type_op/outlives.rs similarity index 97% rename from src/librustc/traits/query/type_op/outlives.rs rename to src/librustc_trait_selection/traits/query/type_op/outlives.rs index 35afa637968..b94948cffd6 100644 --- a/src/librustc/traits/query/type_op/outlives.rs +++ b/src/librustc_trait_selection/traits/query/type_op/outlives.rs @@ -1,7 +1,7 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult}; use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; +use rustc::ty::{ParamEnvAnd, Ty, TyCtxt}; #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)] pub struct DropckOutlives<'tcx> { diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs similarity index 96% rename from src/librustc/traits/query/type_op/prove_predicate.rs rename to src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs index 92cfb82e27e..8c68f7db9e5 100644 --- a/src/librustc/traits/query/type_op/prove_predicate.rs +++ b/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs @@ -1,6 +1,6 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, Predicate, TyCtxt}; +use rustc::ty::{ParamEnvAnd, Predicate, TyCtxt}; pub use rustc::traits::query::type_op::ProvePredicate; diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc_trait_selection/traits/query/type_op/subtype.rs similarity index 94% rename from src/librustc/traits/query/type_op/subtype.rs rename to src/librustc_trait_selection/traits/query/type_op/subtype.rs index 2877a74aaff..053411b0cac 100644 --- a/src/librustc/traits/query/type_op/subtype.rs +++ b/src/librustc_trait_selection/traits/query/type_op/subtype.rs @@ -1,6 +1,6 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, TyCtxt}; +use rustc::ty::{ParamEnvAnd, TyCtxt}; pub use rustc::traits::query::type_op::Subtype; diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs new file mode 100644 index 00000000000..ab3214d8d2d --- /dev/null +++ b/src/librustc_trait_selection/traits/select.rs @@ -0,0 +1,3790 @@ +// ignore-tidy-filelength + +//! Candidate selection. See the [rustc dev guide] for more information on how this works. +//! +//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection + +use self::EvaluationResult::*; +use self::SelectionCandidate::*; + +use super::coherence::{self, Conflict}; +use super::project; +use super::project::{normalize_with_depth, normalize_with_depth_to}; +use super::util; +use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use super::wf; +use super::DerivedObligationCause; +use super::Selection; +use super::SelectionResult; +use super::TraitNotObjectSafe; +use super::TraitQueryMode; +use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode}; +use super::{Normalized, ProjectionCacheKey}; +use super::{ObjectCastObligation, Obligation}; +use super::{ObligationCause, PredicateObligation, TraitObligation}; +use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented}; +use super::{ + VtableAutoImpl, VtableBuiltin, VtableClosure, VtableFnPointer, VtableGenerator, VtableImpl, + VtableObject, VtableParam, VtableTraitAlias, +}; +use super::{ + VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableFnPointerData, + VtableGeneratorData, VtableImplData, VtableObjectData, VtableTraitAliasData, +}; + +use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener}; +use crate::traits::error_reporting::InferCtxtExt; +use crate::traits::project::ProjectionCacheKeyExt; +use rustc::dep_graph::{DepKind, DepNodeIndex}; +use rustc::middle::lang_items; +use rustc::ty::fast_reject; +use rustc::ty::relate::TypeRelation; +use rustc::ty::subst::{Subst, SubstsRef}; +use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; +use rustc_ast::attr; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_index::bit_set::GrowableBitSet; +use rustc_span::symbol::sym; +use rustc_target::spec::abi::Abi; + +use std::cell::{Cell, RefCell}; +use std::cmp; +use std::fmt::{self, Display}; +use std::iter; +use std::rc::Rc; + +pub use rustc::traits::select::*; + +pub struct SelectionContext<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + + /// Freshener used specifically for entries on the obligation + /// stack. This ensures that all entries on the stack at one time + /// will have the same set of placeholder entries, which is + /// important for checking for trait bounds that recursively + /// require themselves. + freshener: TypeFreshener<'cx, 'tcx>, + + /// If `true`, indicates that the evaluation should be conservative + /// and consider the possibility of types outside this crate. + /// This comes up primarily when resolving ambiguity. Imagine + /// there is some trait reference `$0: Bar` where `$0` is an + /// inference variable. If `intercrate` is true, then we can never + /// say for sure that this reference is not implemented, even if + /// there are *no impls at all for `Bar`*, because `$0` could be + /// bound to some type that in a downstream crate that implements + /// `Bar`. This is the suitable mode for coherence. Elsewhere, + /// though, we set this to false, because we are only interested + /// in types that the user could actually have written --- in + /// other words, we consider `$0: Bar` to be unimplemented if + /// there is no type that the user could *actually name* that + /// would satisfy it. This avoids crippling inference, basically. + intercrate: bool, + + intercrate_ambiguity_causes: Option>, + + /// Controls whether or not to filter out negative impls when selecting. + /// This is used in librustdoc to distinguish between the lack of an impl + /// and a negative impl + allow_negative_impls: bool, + + /// The mode that trait queries run in, which informs our error handling + /// policy. In essence, canonicalized queries need their errors propagated + /// rather than immediately reported because we do not have accurate spans. + query_mode: TraitQueryMode, +} + +// A stack that walks back up the stack frame. +struct TraitObligationStack<'prev, 'tcx> { + obligation: &'prev TraitObligation<'tcx>, + + /// The trait ref from `obligation` but "freshened" with the + /// selection-context's freshener. Used to check for recursion. + fresh_trait_ref: ty::PolyTraitRef<'tcx>, + + /// Starts out equal to `depth` -- if, during evaluation, we + /// encounter a cycle, then we will set this flag to the minimum + /// depth of that cycle for all participants in the cycle. These + /// participants will then forego caching their results. This is + /// not the most efficient solution, but it addresses #60010. The + /// problem we are trying to prevent: + /// + /// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait` + /// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok) + /// - `C: NonAutoTrait` requires `A: AutoTrait` (non-coinductive cycle, not ok) + /// + /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait` + /// is `EvaluatedToOk`; this is because they were only considered + /// ok on the premise that if `A: AutoTrait` held, but we indeed + /// encountered a problem (later on) with `A: AutoTrait. So we + /// currently set a flag on the stack node for `B: AutoTrait` (as + /// well as the second instance of `A: AutoTrait`) to suppress + /// caching. + /// + /// This is a simple, targeted fix. A more-performant fix requires + /// deeper changes, but would permit more caching: we could + /// basically defer caching until we have fully evaluated the + /// tree, and then cache the entire tree at once. In any case, the + /// performance impact here shouldn't be so horrible: every time + /// this is hit, we do cache at least one trait, so we only + /// evaluate each member of a cycle up to N times, where N is the + /// length of the cycle. This means the performance impact is + /// bounded and we shouldn't have any terrible worst-cases. + reached_depth: Cell, + + previous: TraitObligationStackList<'prev, 'tcx>, + + /// The number of parent frames plus one (thus, the topmost frame has depth 1). + depth: usize, + + /// The depth-first number of this node in the search graph -- a + /// pre-order index. Basically, a freshly incremented counter. + dfn: usize, +} + +struct SelectionCandidateSet<'tcx> { + // A list of candidates that definitely apply to the current + // obligation (meaning: types unify). + vec: Vec>, + + // If `true`, then there were candidates that might or might + // not have applied, but we couldn't tell. This occurs when some + // of the input types are type variables, in which case there are + // various "builtin" rules that might or might not trigger. + ambiguous: bool, +} + +#[derive(PartialEq, Eq, Debug, Clone)] +struct EvaluatedCandidate<'tcx> { + candidate: SelectionCandidate<'tcx>, + evaluation: EvaluationResult, +} + +/// When does the builtin impl for `T: Trait` apply? +enum BuiltinImplConditions<'tcx> { + /// The impl is conditional on `T1, T2, ...: Trait`. + Where(ty::Binder>>), + /// There is no built-in impl. There may be some other + /// candidate (a where-clause or user-defined impl). + None, + /// It is unknown whether there is an impl. + Ambiguous, +} + +impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { + SelectionContext { + infcx, + freshener: infcx.freshener(), + intercrate: false, + intercrate_ambiguity_causes: None, + allow_negative_impls: false, + query_mode: TraitQueryMode::Standard, + } + } + + pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { + SelectionContext { + infcx, + freshener: infcx.freshener(), + intercrate: true, + intercrate_ambiguity_causes: None, + allow_negative_impls: false, + query_mode: TraitQueryMode::Standard, + } + } + + pub fn with_negative( + infcx: &'cx InferCtxt<'cx, 'tcx>, + allow_negative_impls: bool, + ) -> SelectionContext<'cx, 'tcx> { + debug!("with_negative({:?})", allow_negative_impls); + SelectionContext { + infcx, + freshener: infcx.freshener(), + intercrate: false, + intercrate_ambiguity_causes: None, + allow_negative_impls, + query_mode: TraitQueryMode::Standard, + } + } + + pub fn with_query_mode( + infcx: &'cx InferCtxt<'cx, 'tcx>, + query_mode: TraitQueryMode, + ) -> SelectionContext<'cx, 'tcx> { + debug!("with_query_mode({:?})", query_mode); + SelectionContext { + infcx, + freshener: infcx.freshener(), + intercrate: false, + intercrate_ambiguity_causes: None, + allow_negative_impls: false, + query_mode, + } + } + + /// Enables tracking of intercrate ambiguity causes. These are + /// used in coherence to give improved diagnostics. We don't do + /// this until we detect a coherence error because it can lead to + /// false overflow results (#47139) and because it costs + /// computation time. + pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { + assert!(self.intercrate); + assert!(self.intercrate_ambiguity_causes.is_none()); + self.intercrate_ambiguity_causes = Some(vec![]); + debug!("selcx: enable_tracking_intercrate_ambiguity_causes"); + } + + /// Gets the intercrate ambiguity causes collected since tracking + /// was enabled and disables tracking at the same time. If + /// tracking is not enabled, just returns an empty vector. + pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec { + assert!(self.intercrate); + self.intercrate_ambiguity_causes.take().unwrap_or(vec![]) + } + + pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> { + self.infcx + } + + pub fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> { + self.infcx + } + + /////////////////////////////////////////////////////////////////////////// + // Selection + // + // The selection phase tries to identify *how* an obligation will + // be resolved. For example, it will identify which impl or + // parameter bound is to be used. The process can be inconclusive + // if the self type in the obligation is not fully inferred. Selection + // can result in an error in one of two ways: + // + // 1. If no applicable impl or parameter bound can be found. + // 2. If the output type parameters in the obligation do not match + // those specified by the impl/bound. For example, if the obligation + // is `Vec: Iterable`, but the impl specifies + // `impl Iterable for Vec`, than an error would result. + + /// Attempts to satisfy the obligation. If successful, this will affect the surrounding + /// type environment by performing unification. + pub fn select( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> SelectionResult<'tcx, Selection<'tcx>> { + debug!("select({:?})", obligation); + debug_assert!(!obligation.predicate.has_escaping_bound_vars()); + + let pec = &ProvisionalEvaluationCache::default(); + let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation); + + let candidate = match self.candidate_from_obligation(&stack) { + Err(SelectionError::Overflow) => { + // In standard mode, overflow must have been caught and reported + // earlier. + assert!(self.query_mode == TraitQueryMode::Canonical); + return Err(SelectionError::Overflow); + } + Err(e) => { + return Err(e); + } + Ok(None) => { + return Ok(None); + } + Ok(Some(candidate)) => candidate, + }; + + match self.confirm_candidate(obligation, candidate) { + Err(SelectionError::Overflow) => { + assert!(self.query_mode == TraitQueryMode::Canonical); + Err(SelectionError::Overflow) + } + Err(e) => Err(e), + Ok(candidate) => Ok(Some(candidate)), + } + } + + /////////////////////////////////////////////////////////////////////////// + // EVALUATION + // + // Tests whether an obligation can be selected or whether an impl + // can be applied to particular types. It skips the "confirmation" + // step and hence completely ignores output type parameters. + // + // The result is "true" if the obligation *may* hold and "false" if + // we can be sure it does not. + + /// Evaluates whether the obligation `obligation` can be satisfied (by any means). + pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool { + debug!("predicate_may_hold_fatal({:?})", obligation); + + // This fatal query is a stopgap that should only be used in standard mode, + // where we do not expect overflow to be propagated. + assert!(self.query_mode == TraitQueryMode::Standard); + + self.evaluate_root_obligation(obligation) + .expect("Overflow should be caught earlier in standard query mode") + .may_apply() + } + + /// Evaluates whether the obligation `obligation` can be satisfied + /// and returns an `EvaluationResult`. This is meant for the + /// *initial* call. + pub fn evaluate_root_obligation( + &mut self, + obligation: &PredicateObligation<'tcx>, + ) -> Result { + self.evaluation_probe(|this| { + this.evaluate_predicate_recursively( + TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), + obligation.clone(), + ) + }) + } + + fn evaluation_probe( + &mut self, + op: impl FnOnce(&mut Self) -> Result, + ) -> Result { + self.infcx.probe(|snapshot| -> Result { + let result = op(self)?; + match self.infcx.region_constraints_added_in_snapshot(snapshot) { + None => Ok(result), + Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), + } + }) + } + + /// Evaluates the predicates in `predicates` recursively. Note that + /// this applies projections in the predicates, and therefore + /// is run within an inference probe. + fn evaluate_predicates_recursively<'o, I>( + &mut self, + stack: TraitObligationStackList<'o, 'tcx>, + predicates: I, + ) -> Result + where + I: IntoIterator>, + { + let mut result = EvaluatedToOk; + for obligation in predicates { + let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; + debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval); + if let EvaluatedToErr = eval { + // fast-path - EvaluatedToErr is the top of the lattice, + // so we don't need to look on the other predicates. + return Ok(EvaluatedToErr); + } else { + result = cmp::max(result, eval); + } + } + Ok(result) + } + + fn evaluate_predicate_recursively<'o>( + &mut self, + previous_stack: TraitObligationStackList<'o, 'tcx>, + obligation: PredicateObligation<'tcx>, + ) -> Result { + debug!( + "evaluate_predicate_recursively(previous_stack={:?}, obligation={:?})", + previous_stack.head(), + obligation + ); + + // `previous_stack` stores a `TraitObligatiom`, while `obligation` is + // a `PredicateObligation`. These are distinct types, so we can't + // use any `Option` combinator method that would force them to be + // the same. + match previous_stack.head() { + Some(h) => self.check_recursion_limit(&obligation, h.obligation)?, + None => self.check_recursion_limit(&obligation, &obligation)?, + } + + match obligation.predicate { + ty::Predicate::Trait(ref t, _) => { + debug_assert!(!t.has_escaping_bound_vars()); + let obligation = obligation.with(t.clone()); + self.evaluate_trait_predicate_recursively(previous_stack, obligation) + } + + ty::Predicate::Subtype(ref p) => { + // Does this code ever run? + match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { + Some(Ok(InferOk { mut obligations, .. })) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively( + previous_stack, + obligations.into_iter(), + ) + } + Some(Err(_)) => Ok(EvaluatedToErr), + None => Ok(EvaluatedToAmbig), + } + } + + ty::Predicate::WellFormed(ty) => match wf::obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_id, + ty, + obligation.cause.span, + ) { + Some(mut obligations) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) + } + None => Ok(EvaluatedToAmbig), + }, + + ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { + // We do not consider region relationships when evaluating trait matches. + Ok(EvaluatedToOkModuloRegions) + } + + ty::Predicate::ObjectSafe(trait_def_id) => { + if self.tcx().is_object_safe(trait_def_id) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToErr) + } + } + + ty::Predicate::Projection(ref data) => { + let project_obligation = obligation.with(data.clone()); + match project::poly_project_and_unify_type(self, &project_obligation) { + Ok(Some(mut subobligations)) => { + self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); + let result = self.evaluate_predicates_recursively( + previous_stack, + subobligations.into_iter(), + ); + if let Some(key) = + ProjectionCacheKey::from_poly_projection_predicate(self, data) + { + self.infcx.inner.borrow_mut().projection_cache.complete(key); + } + result + } + Ok(None) => Ok(EvaluatedToAmbig), + Err(_) => Ok(EvaluatedToErr), + } + } + + ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { + match self.infcx.closure_kind(closure_def_id, closure_substs) { + Some(closure_kind) => { + if closure_kind.extends(kind) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToErr) + } + } + None => Ok(EvaluatedToAmbig), + } + } + + ty::Predicate::ConstEvaluatable(def_id, substs) => { + match self.tcx().const_eval_resolve( + obligation.param_env, + def_id, + substs, + None, + None, + ) { + Ok(_) => Ok(EvaluatedToOk), + Err(_) => Ok(EvaluatedToErr), + } + } + } + } + + fn evaluate_trait_predicate_recursively<'o>( + &mut self, + previous_stack: TraitObligationStackList<'o, 'tcx>, + mut obligation: TraitObligation<'tcx>, + ) -> Result { + debug!("evaluate_trait_predicate_recursively({:?})", obligation); + + if !self.intercrate + && obligation.is_global() + && obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst()) + { + // If a param env has no global bounds, global obligations do not + // depend on its particular value in order to work, so we can clear + // out the param env and get better caching. + debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation); + obligation.param_env = obligation.param_env.without_caller_bounds(); + } + + let stack = self.push_stack(previous_stack, &obligation); + let fresh_trait_ref = stack.fresh_trait_ref; + if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) { + debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); + return Ok(result); + } + + if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) { + debug!("PROVISIONAL CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); + stack.update_reached_depth(stack.cache().current_reached_depth()); + return Ok(result); + } + + // Check if this is a match for something already on the + // stack. If so, we don't want to insert the result into the + // main cache (it is cycle dependent) nor the provisional + // cache (which is meant for things that have completed but + // for a "backedge" -- this result *is* the backedge). + if let Some(cycle_result) = self.check_evaluation_cycle(&stack) { + return Ok(cycle_result); + } + + let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); + let result = result?; + + if !result.must_apply_modulo_regions() { + stack.cache().on_failure(stack.dfn); + } + + let reached_depth = stack.reached_depth.get(); + if reached_depth >= stack.depth { + debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); + self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result); + + stack.cache().on_completion(stack.depth, |fresh_trait_ref, provisional_result| { + self.insert_evaluation_cache( + obligation.param_env, + fresh_trait_ref, + dep_node, + provisional_result.max(result), + ); + }); + } else { + debug!("PROVISIONAL: {:?}={:?}", fresh_trait_ref, result); + debug!( + "evaluate_trait_predicate_recursively: caching provisionally because {:?} \ + is a cycle participant (at depth {}, reached depth {})", + fresh_trait_ref, stack.depth, reached_depth, + ); + + stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result); + } + + Ok(result) + } + + /// If there is any previous entry on the stack that precisely + /// matches this obligation, then we can assume that the + /// obligation is satisfied for now (still all other conditions + /// must be met of course). One obvious case this comes up is + /// marker traits like `Send`. Think of a linked list: + /// + /// struct List { data: T, next: Option>> } + /// + /// `Box>` will be `Send` if `T` is `Send` and + /// `Option>>` is `Send`, and in turn + /// `Option>>` is `Send` if `Box>` is + /// `Send`. + /// + /// Note that we do this comparison using the `fresh_trait_ref` + /// fields. Because these have all been freshened using + /// `self.freshener`, we can be sure that (a) this will not + /// affect the inferencer state and (b) that if we see two + /// fresh regions with the same index, they refer to the same + /// unbound type variable. + fn check_evaluation_cycle( + &mut self, + stack: &TraitObligationStack<'_, 'tcx>, + ) -> Option { + if let Some(cycle_depth) = stack + .iter() + .skip(1) // Skip top-most frame. + .find(|prev| { + stack.obligation.param_env == prev.obligation.param_env + && stack.fresh_trait_ref == prev.fresh_trait_ref + }) + .map(|stack| stack.depth) + { + debug!( + "evaluate_stack({:?}) --> recursive at depth {}", + stack.fresh_trait_ref, cycle_depth, + ); + + // If we have a stack like `A B C D E A`, where the top of + // the stack is the final `A`, then this will iterate over + // `A, E, D, C, B` -- i.e., all the participants apart + // from the cycle head. We mark them as participating in a + // cycle. This suppresses caching for those nodes. See + // `in_cycle` field for more details. + stack.update_reached_depth(cycle_depth); + + // Subtle: when checking for a coinductive cycle, we do + // not compare using the "freshened trait refs" (which + // have erased regions) but rather the fully explicit + // trait refs. This is important because it's only a cycle + // if the regions match exactly. + let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth); + let cycle = cycle.map(|stack| { + ty::Predicate::Trait(stack.obligation.predicate, hir::Constness::NotConst) + }); + if self.coinductive_match(cycle) { + debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); + Some(EvaluatedToOk) + } else { + debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref); + Some(EvaluatedToRecur) + } + } else { + None + } + } + + fn evaluate_stack<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> Result { + // In intercrate mode, whenever any of the types are unbound, + // there can always be an impl. Even if there are no impls in + // this crate, perhaps the type would be unified with + // something from another crate that does provide an impl. + // + // In intra mode, we must still be conservative. The reason is + // that we want to avoid cycles. Imagine an impl like: + // + // impl Eq for Vec + // + // and a trait reference like `$0 : Eq` where `$0` is an + // unbound variable. When we evaluate this trait-reference, we + // will unify `$0` with `Vec<$1>` (for some fresh variable + // `$1`), on the condition that `$1 : Eq`. We will then wind + // up with many candidates (since that are other `Eq` impls + // that apply) and try to winnow things down. This results in + // a recursive evaluation that `$1 : Eq` -- as you can + // imagine, this is just where we started. To avoid that, we + // check for unbound variables and return an ambiguous (hence possible) + // match if we've seen this trait before. + // + // This suffices to allow chains like `FnMut` implemented in + // terms of `Fn` etc, but we could probably make this more + // precise still. + let unbound_input_types = + stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh()); + // This check was an imperfect workaround for a bug in the old + // intercrate mode; it should be removed when that goes away. + if unbound_input_types && self.intercrate { + debug!( + "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", + stack.fresh_trait_ref + ); + // Heuristics: show the diagnostics when there are no candidates in crate. + if self.intercrate_ambiguity_causes.is_some() { + debug!("evaluate_stack: intercrate_ambiguity_causes is some"); + if let Ok(candidate_set) = self.assemble_candidates(stack) { + if !candidate_set.ambiguous && candidate_set.vec.is_empty() { + let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let self_ty = trait_ref.self_ty(); + let cause = IntercrateAmbiguityCause::DownstreamCrate { + trait_desc: trait_ref.print_only_trait_path().to_string(), + self_desc: if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }, + }; + debug!("evaluate_stack: pushing cause = {:?}", cause); + self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + } + } + } + return Ok(EvaluatedToAmbig); + } + if unbound_input_types + && stack.iter().skip(1).any(|prev| { + stack.obligation.param_env == prev.obligation.param_env + && self.match_fresh_trait_refs( + &stack.fresh_trait_ref, + &prev.fresh_trait_ref, + prev.obligation.param_env, + ) + }) + { + debug!( + "evaluate_stack({:?}) --> unbound argument, recursive --> giving up", + stack.fresh_trait_ref + ); + return Ok(EvaluatedToUnknown); + } + + match self.candidate_from_obligation(stack) { + Ok(Some(c)) => self.evaluate_candidate(stack, &c), + Ok(None) => Ok(EvaluatedToAmbig), + Err(Overflow) => Err(OverflowError), + Err(..) => Ok(EvaluatedToErr), + } + } + + /// For defaulted traits, we use a co-inductive strategy to solve, so + /// that recursion is ok. This routine returns `true` if the top of the + /// stack (`cycle[0]`): + /// + /// - is a defaulted trait, + /// - it also appears in the backtrace at some position `X`, + /// - all the predicates at positions `X..` between `X` and the top are + /// also defaulted traits. + pub fn coinductive_match(&mut self, cycle: I) -> bool + where + I: Iterator>, + { + let mut cycle = cycle; + cycle.all(|predicate| self.coinductive_predicate(predicate)) + } + + fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { + let result = match predicate { + ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), + _ => false, + }; + debug!("coinductive_predicate({:?}) = {:?}", predicate, result); + result + } + + /// Further evaluates `candidate` to decide whether all type parameters match and whether nested + /// obligations are met. Returns whether `candidate` remains viable after this further + /// scrutiny. + fn evaluate_candidate<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + candidate: &SelectionCandidate<'tcx>, + ) -> Result { + debug!( + "evaluate_candidate: depth={} candidate={:?}", + stack.obligation.recursion_depth, candidate + ); + let result = self.evaluation_probe(|this| { + let candidate = (*candidate).clone(); + match this.confirm_candidate(stack.obligation, candidate) { + Ok(selection) => this.evaluate_predicates_recursively( + stack.list(), + selection.nested_obligations().into_iter(), + ), + Err(..) => Ok(EvaluatedToErr), + } + })?; + debug!( + "evaluate_candidate: depth={} result={:?}", + stack.obligation.recursion_depth, result + ); + Ok(result) + } + + fn check_evaluation_cache( + &self, + param_env: ty::ParamEnv<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Option { + let tcx = self.tcx(); + if self.can_use_global_caches(param_env) { + let cache = tcx.evaluation_cache.hashmap.borrow(); + if let Some(cached) = cache.get(¶m_env.and(trait_ref)) { + return Some(cached.get(tcx)); + } + } + self.infcx + .evaluation_cache + .hashmap + .borrow() + .get(¶m_env.and(trait_ref)) + .map(|v| v.get(tcx)) + } + + fn insert_evaluation_cache( + &mut self, + param_env: ty::ParamEnv<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + dep_node: DepNodeIndex, + result: EvaluationResult, + ) { + // Avoid caching results that depend on more than just the trait-ref + // - the stack can create recursion. + if result.is_stack_dependent() { + return; + } + + if self.can_use_global_caches(param_env) { + if !trait_ref.has_local_value() { + debug!( + "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global", + trait_ref, result, + ); + // This may overwrite the cache with the same value + // FIXME: Due to #50507 this overwrites the different values + // This should be changed to use HashMapExt::insert_same + // when that is fixed + self.tcx() + .evaluation_cache + .hashmap + .borrow_mut() + .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result)); + return; + } + } + + debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,); + self.infcx + .evaluation_cache + .hashmap + .borrow_mut() + .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result)); + } + + /// For various reasons, it's possible for a subobligation + /// to have a *lower* recursion_depth than the obligation used to create it. + /// Projection sub-obligations may be returned from the projection cache, + /// which results in obligations with an 'old' `recursion_depth`. + /// Additionally, methods like `wf::obligations` and + /// `InferCtxt.subtype_predicate` produce subobligations without + /// taking in a 'parent' depth, causing the generated subobligations + /// to have a `recursion_depth` of `0`. + /// + /// To ensure that obligation_depth never decreasees, we force all subobligations + /// to have at least the depth of the original obligation. + fn add_depth>>( + &self, + it: I, + min_depth: usize, + ) { + it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); + } + + /// Checks that the recursion limit has not been exceeded. + /// + /// The weird return type of this function allows it to be used with the `try` (`?`) + /// operator within certain functions. + fn check_recursion_limit, V: Display + TypeFoldable<'tcx>>( + &self, + obligation: &Obligation<'tcx, T>, + error_obligation: &Obligation<'tcx, V>, + ) -> Result<(), OverflowError> { + let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); + if obligation.recursion_depth >= recursion_limit { + match self.query_mode { + TraitQueryMode::Standard => { + self.infcx().report_overflow_error(error_obligation, true); + } + TraitQueryMode::Canonical => { + return Err(OverflowError); + } + } + } + Ok(()) + } + + /////////////////////////////////////////////////////////////////////////// + // CANDIDATE ASSEMBLY + // + // The selection process begins by examining all in-scope impls, + // caller obligations, and so forth and assembling a list of + // candidates. See the [rustc dev guide] for more details. + // + // [rustc dev guide]: + // https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly + + fn candidate_from_obligation<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + // Watch out for overflow. This intentionally bypasses (and does + // not update) the cache. + self.check_recursion_limit(&stack.obligation, &stack.obligation)?; + + // Check the cache. Note that we freshen the trait-ref + // separately rather than using `stack.fresh_trait_ref` -- + // this is because we want the unbound variables to be + // replaced with fresh types starting from index 0. + let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate.clone()); + debug!( + "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})", + cache_fresh_trait_pred, stack + ); + debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars()); + + if let Some(c) = + self.check_candidate_cache(stack.obligation.param_env, &cache_fresh_trait_pred) + { + debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c); + return c; + } + + // If no match, compute result and insert into cache. + // + // FIXME(nikomatsakis) -- this cache is not taking into + // account cycles that may have occurred in forming the + // candidate. I don't know of any specific problems that + // result but it seems awfully suspicious. + let (candidate, dep_node) = + self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); + + debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate); + self.insert_candidate_cache( + stack.obligation.param_env, + cache_fresh_trait_pred, + dep_node, + candidate.clone(), + ); + candidate + } + + fn in_task(&mut self, op: OP) -> (R, DepNodeIndex) + where + OP: FnOnce(&mut Self) -> R, + { + let (result, dep_node) = + self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || op(self)); + self.tcx().dep_graph.read_index(dep_node); + (result, dep_node) + } + + // Treat negative impls as unimplemented, and reservation impls as ambiguity. + fn filter_negative_and_reservation_impls( + &mut self, + candidate: SelectionCandidate<'tcx>, + ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + if let ImplCandidate(def_id) = candidate { + let tcx = self.tcx(); + match tcx.impl_polarity(def_id) { + ty::ImplPolarity::Negative if !self.allow_negative_impls => { + return Err(Unimplemented); + } + ty::ImplPolarity::Reservation => { + if let Some(intercrate_ambiguity_clauses) = + &mut self.intercrate_ambiguity_causes + { + let attrs = tcx.get_attrs(def_id); + let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl); + let value = attr.and_then(|a| a.value_str()); + if let Some(value) = value { + debug!( + "filter_negative_and_reservation_impls: \ + reservation impl ambiguity on {:?}", + def_id + ); + intercrate_ambiguity_clauses.push( + IntercrateAmbiguityCause::ReservationImpl { + message: value.to_string(), + }, + ); + } + } + return Ok(None); + } + _ => {} + }; + } + Ok(Some(candidate)) + } + + fn candidate_from_obligation_no_cache<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + if stack.obligation.predicate.references_error() { + // If we encounter a `Error`, we generally prefer the + // most "optimistic" result in response -- that is, the + // one least likely to report downstream errors. But + // because this routine is shared by coherence and by + // trait selection, there isn't an obvious "right" choice + // here in that respect, so we opt to just return + // ambiguity and let the upstream clients sort it out. + return Ok(None); + } + + if let Some(conflict) = self.is_knowable(stack) { + debug!("coherence stage: not knowable"); + if self.intercrate_ambiguity_causes.is_some() { + debug!("evaluate_stack: intercrate_ambiguity_causes is some"); + // Heuristics: show the diagnostics when there are no candidates in crate. + if let Ok(candidate_set) = self.assemble_candidates(stack) { + let mut no_candidates_apply = true; + { + let evaluated_candidates = + candidate_set.vec.iter().map(|c| self.evaluate_candidate(stack, &c)); + + for ec in evaluated_candidates { + match ec { + Ok(c) => { + if c.may_apply() { + no_candidates_apply = false; + break; + } + } + Err(e) => return Err(e.into()), + } + } + } + + if !candidate_set.ambiguous && no_candidates_apply { + let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let self_ty = trait_ref.self_ty(); + let trait_desc = trait_ref.print_only_trait_path().to_string(); + let self_desc = if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }; + let cause = if let Conflict::Upstream = conflict { + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } + } else { + IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } + }; + debug!("evaluate_stack: pushing cause = {:?}", cause); + self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + } + } + } + return Ok(None); + } + + let candidate_set = self.assemble_candidates(stack)?; + + if candidate_set.ambiguous { + debug!("candidate set contains ambig"); + return Ok(None); + } + + let mut candidates = candidate_set.vec; + + debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + + // At this point, we know that each of the entries in the + // candidate set is *individually* applicable. Now we have to + // figure out if they contain mutual incompatibilities. This + // frequently arises if we have an unconstrained input type -- + // for example, we are looking for `$0: Eq` where `$0` is some + // unconstrained type variable. In that case, we'll get a + // candidate which assumes $0 == int, one that assumes `$0 == + // usize`, etc. This spells an ambiguity. + + // If there is more than one candidate, first winnow them down + // by considering extra conditions (nested obligations and so + // forth). We don't winnow if there is exactly one + // candidate. This is a relatively minor distinction but it + // can lead to better inference and error-reporting. An + // example would be if there was an impl: + // + // impl Vec { fn push_clone(...) { ... } } + // + // and we were to see some code `foo.push_clone()` where `boo` + // is a `Vec` and `Bar` does not implement `Clone`. If + // we were to winnow, we'd wind up with zero candidates. + // Instead, we select the right impl now but report "`Bar` does + // not implement `Clone`". + if candidates.len() == 1 { + return self.filter_negative_and_reservation_impls(candidates.pop().unwrap()); + } + + // Winnow, but record the exact outcome of evaluation, which + // is needed for specialization. Propagate overflow if it occurs. + let mut candidates = candidates + .into_iter() + .map(|c| match self.evaluate_candidate(stack, &c) { + Ok(eval) if eval.may_apply() => { + Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) + } + Ok(_) => Ok(None), + Err(OverflowError) => Err(Overflow), + }) + .flat_map(Result::transpose) + .collect::, _>>()?; + + debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + + let needs_infer = stack.obligation.predicate.needs_infer(); + + // If there are STILL multiple candidates, we can further + // reduce the list by dropping duplicates -- including + // resolving specializations. + if candidates.len() > 1 { + let mut i = 0; + while i < candidates.len() { + let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { + self.candidate_should_be_dropped_in_favor_of( + &candidates[i], + &candidates[j], + needs_infer, + ) + }); + if is_dup { + debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + candidates.swap_remove(i); + } else { + debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + i += 1; + + // If there are *STILL* multiple candidates, give up + // and report ambiguity. + if i > 1 { + debug!("multiple matches, ambig"); + return Ok(None); + } + } + } + } + + // If there are *NO* candidates, then there are no impls -- + // that we know of, anyway. Note that in the case where there + // are unbound type variables within the obligation, it might + // be the case that you could still satisfy the obligation + // from another crate by instantiating the type variables with + // a type from another crate that does have an impl. This case + // is checked for in `evaluate_stack` (and hence users + // who might care about this case, like coherence, should use + // that function). + if candidates.is_empty() { + return Err(Unimplemented); + } + + // Just one candidate left. + self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate) + } + + fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option { + debug!("is_knowable(intercrate={:?})", self.intercrate); + + if !self.intercrate { + return None; + } + + let obligation = &stack.obligation; + let predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); + + // Okay to skip binder because of the nature of the + // trait-ref-is-knowable check, which does not care about + // bound regions. + let trait_ref = predicate.skip_binder().trait_ref; + + coherence::trait_ref_is_knowable(self.tcx(), trait_ref) + } + + /// Returns `true` if the global caches can be used. + /// Do note that if the type itself is not in the + /// global tcx, the local caches will be used. + fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool { + // If there are any e.g. inference variables in the `ParamEnv`, then we + // always use a cache local to this particular scope. Otherwise, we + // switch to a global cache. + if param_env.has_local_value() { + return false; + } + + // Avoid using the master cache during coherence and just rely + // on the local cache. This effectively disables caching + // during coherence. It is really just a simplification to + // avoid us having to fear that coherence results "pollute" + // the master cache. Since coherence executes pretty quickly, + // it's not worth going to more trouble to increase the + // hit-rate, I don't think. + if self.intercrate { + return false; + } + + // Otherwise, we can use the global cache. + true + } + + fn check_candidate_cache( + &mut self, + param_env: ty::ParamEnv<'tcx>, + cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>, + ) -> Option>> { + let tcx = self.tcx(); + let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref; + if self.can_use_global_caches(param_env) { + let cache = tcx.selection_cache.hashmap.borrow(); + if let Some(cached) = cache.get(¶m_env.and(*trait_ref)) { + return Some(cached.get(tcx)); + } + } + self.infcx + .selection_cache + .hashmap + .borrow() + .get(¶m_env.and(*trait_ref)) + .map(|v| v.get(tcx)) + } + + /// Determines whether can we safely cache the result + /// of selecting an obligation. This is almost always `true`, + /// except when dealing with certain `ParamCandidate`s. + /// + /// Ordinarily, a `ParamCandidate` will contain no inference variables, + /// since it was usually produced directly from a `DefId`. However, + /// certain cases (currently only librustdoc's blanket impl finder), + /// a `ParamEnv` may be explicitly constructed with inference types. + /// When this is the case, we do *not* want to cache the resulting selection + /// candidate. This is due to the fact that it might not always be possible + /// to equate the obligation's trait ref and the candidate's trait ref, + /// if more constraints end up getting added to an inference variable. + /// + /// Because of this, we always want to re-run the full selection + /// process for our obligation the next time we see it, since + /// we might end up picking a different `SelectionCandidate` (or none at all). + fn can_cache_candidate( + &self, + result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, + ) -> bool { + match result { + Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => { + !trait_ref.skip_binder().input_types().any(|t| t.walk().any(|t_| t_.is_ty_infer())) + } + _ => true, + } + } + + fn insert_candidate_cache( + &mut self, + param_env: ty::ParamEnv<'tcx>, + cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + dep_node: DepNodeIndex, + candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>, + ) { + let tcx = self.tcx(); + let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref; + + if !self.can_cache_candidate(&candidate) { + debug!( + "insert_candidate_cache(trait_ref={:?}, candidate={:?} -\ + candidate is not cacheable", + trait_ref, candidate + ); + return; + } + + if self.can_use_global_caches(param_env) { + if let Err(Overflow) = candidate { + // Don't cache overflow globally; we only produce this in certain modes. + } else if !trait_ref.has_local_value() { + if !candidate.has_local_value() { + debug!( + "insert_candidate_cache(trait_ref={:?}, candidate={:?}) global", + trait_ref, candidate, + ); + // This may overwrite the cache with the same value. + tcx.selection_cache + .hashmap + .borrow_mut() + .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate)); + return; + } + } + } + + debug!( + "insert_candidate_cache(trait_ref={:?}, candidate={:?}) local", + trait_ref, candidate, + ); + self.infcx + .selection_cache + .hashmap + .borrow_mut() + .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate)); + } + + fn assemble_candidates<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> Result, SelectionError<'tcx>> { + let TraitObligationStack { obligation, .. } = *stack; + let obligation = &Obligation { + param_env: obligation.param_env, + cause: obligation.cause.clone(), + recursion_depth: obligation.recursion_depth, + predicate: self.infcx().resolve_vars_if_possible(&obligation.predicate), + }; + + if obligation.predicate.skip_binder().self_ty().is_ty_var() { + // Self is a type variable (e.g., `_: AsRef`). + // + // This is somewhat problematic, as the current scheme can't really + // handle it turning to be a projection. This does end up as truly + // ambiguous in most cases anyway. + // + // Take the fast path out - this also improves + // performance by preventing assemble_candidates_from_impls from + // matching every impl for this trait. + return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true }); + } + + let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; + + self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?; + + // Other bounds. Consider both in-scope bounds from fn decl + // and applicable impls. There is a certain set of precedence rules here. + let def_id = obligation.predicate.def_id(); + let lang_items = self.tcx().lang_items(); + + if lang_items.copy_trait() == Some(def_id) { + debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty()); + + // User-defined copy impls are permitted, but only for + // structs and enums. + self.assemble_candidates_from_impls(obligation, &mut candidates)?; + + // For other types, we'll use the builtin rules. + let copy_conditions = self.copy_clone_conditions(obligation); + self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?; + } else if lang_items.sized_trait() == Some(def_id) { + // Sized is never implementable by end-users, it is + // always automatically computed. + let sized_conditions = self.sized_conditions(obligation); + self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?; + } else if lang_items.unsize_trait() == Some(def_id) { + self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } else { + if lang_items.clone_trait() == Some(def_id) { + // Same builtin conditions as `Copy`, i.e., every type which has builtin support + // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone` + // types have builtin support for `Clone`. + let clone_conditions = self.copy_clone_conditions(obligation); + self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?; + } + + self.assemble_generator_candidates(obligation, &mut candidates)?; + self.assemble_closure_candidates(obligation, &mut candidates)?; + self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; + self.assemble_candidates_from_impls(obligation, &mut candidates)?; + self.assemble_candidates_from_object_ty(obligation, &mut candidates); + } + + self.assemble_candidates_from_projected_tys(obligation, &mut candidates); + self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; + // Auto implementations have lower priority, so we only + // consider triggering a default if there is no other impl that can apply. + if candidates.vec.is_empty() { + self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?; + } + debug!("candidate list size: {}", candidates.vec.len()); + Ok(candidates) + } + + fn assemble_candidates_from_projected_tys( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + debug!("assemble_candidates_for_projected_tys({:?})", obligation); + + // Before we go into the whole placeholder thing, just + // quickly check if the self-type is a projection at all. + match obligation.predicate.skip_binder().trait_ref.self_ty().kind { + ty::Projection(_) | ty::Opaque(..) => {} + ty::Infer(ty::TyVar(_)) => { + span_bug!( + obligation.cause.span, + "Self=_ should have been handled by assemble_candidates" + ); + } + _ => return, + } + + let result = self.infcx.probe(|snapshot| { + self.match_projection_obligation_against_definition_bounds(obligation, snapshot) + }); + + if result { + candidates.vec.push(ProjectionCandidate); + } + } + + fn match_projection_obligation_against_definition_bounds( + &mut self, + obligation: &TraitObligation<'tcx>, + snapshot: &CombinedSnapshot<'_, 'tcx>, + ) -> bool { + let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); + let (placeholder_trait_predicate, placeholder_map) = + self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); + debug!( + "match_projection_obligation_against_definition_bounds: \ + placeholder_trait_predicate={:?}", + placeholder_trait_predicate, + ); + + let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind { + ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs), + ty::Opaque(def_id, substs) => (def_id, substs), + _ => { + span_bug!( + obligation.cause.span, + "match_projection_obligation_against_definition_bounds() called \ + but self-ty is not a projection: {:?}", + placeholder_trait_predicate.trait_ref.self_ty() + ); + } + }; + debug!( + "match_projection_obligation_against_definition_bounds: \ + def_id={:?}, substs={:?}", + def_id, substs + ); + + let predicates_of = self.tcx().predicates_of(def_id); + let bounds = predicates_of.instantiate(self.tcx(), substs); + debug!( + "match_projection_obligation_against_definition_bounds: \ + bounds={:?}", + bounds + ); + + let elaborated_predicates = util::elaborate_predicates(self.tcx(), bounds.predicates); + let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| { + self.infcx.probe(|_| { + self.match_projection( + obligation, + bound.clone(), + placeholder_trait_predicate.trait_ref.clone(), + &placeholder_map, + snapshot, + ) + }) + }); + + debug!( + "match_projection_obligation_against_definition_bounds: \ + matching_bound={:?}", + matching_bound + ); + match matching_bound { + None => false, + Some(bound) => { + // Repeat the successful match, if any, this time outside of a probe. + let result = self.match_projection( + obligation, + bound, + placeholder_trait_predicate.trait_ref.clone(), + &placeholder_map, + snapshot, + ); + + assert!(result); + true + } + } + } + + fn match_projection( + &mut self, + obligation: &TraitObligation<'tcx>, + trait_bound: ty::PolyTraitRef<'tcx>, + placeholder_trait_ref: ty::TraitRef<'tcx>, + placeholder_map: &PlaceholderMap<'tcx>, + snapshot: &CombinedSnapshot<'_, 'tcx>, + ) -> bool { + debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars()); + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) + .is_ok() + && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok() + } + + /// Given an obligation like ``, searches the obligations that the caller + /// supplied to find out whether it is listed among them. + /// + /// Never affects the inference environment. + fn assemble_candidates_from_caller_bounds<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation); + + let all_bounds = stack + .obligation + .param_env + .caller_bounds + .iter() + .filter_map(|o| o.to_opt_poly_trait_ref()); + + // Micro-optimization: filter out predicates relating to different traits. + let matching_bounds = + all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); + + // Keep only those bounds which may apply, and propagate overflow if it occurs. + let mut param_candidates = vec![]; + for bound in matching_bounds { + let wc = self.evaluate_where_clause(stack, bound.clone())?; + if wc.may_apply() { + param_candidates.push(ParamCandidate(bound)); + } + } + + candidates.vec.extend(param_candidates); + + Ok(()) + } + + fn evaluate_where_clause<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + where_clause_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result { + self.evaluation_probe(|this| { + match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { + Ok(obligations) => { + this.evaluate_predicates_recursively(stack.list(), obligations.into_iter()) + } + Err(()) => Ok(EvaluatedToErr), + } + }) + } + + fn assemble_generator_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) { + return Ok(()); + } + + // Okay to skip binder because the substs on generator types never + // touch bound regions, they just capture the in-scope + // type/region parameters. + let self_ty = *obligation.self_ty().skip_binder(); + match self_ty.kind { + ty::Generator(..) => { + debug!( + "assemble_generator_candidates: self_ty={:?} obligation={:?}", + self_ty, obligation + ); + + candidates.vec.push(GeneratorCandidate); + } + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_generator_candidates: ambiguous self-type"); + candidates.ambiguous = true; + } + _ => {} + } + + Ok(()) + } + + /// Checks for the artificial impl that the compiler will create for an obligation like `X : + /// FnMut<..>` where `X` is a closure type. + /// + /// Note: the type parameters on a closure candidate are modeled as *output* type + /// parameters and hence do not affect whether this trait is a match or not. They will be + /// unified during the confirmation step. + fn assemble_closure_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + let kind = match self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) { + Some(k) => k, + None => { + return Ok(()); + } + }; + + // Okay to skip binder because the substs on closure types never + // touch bound regions, they just capture the in-scope + // type/region parameters + match obligation.self_ty().skip_binder().kind { + ty::Closure(closure_def_id, closure_substs) => { + debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation); + match self.infcx.closure_kind(closure_def_id, closure_substs) { + Some(closure_kind) => { + debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); + if closure_kind.extends(kind) { + candidates.vec.push(ClosureCandidate); + } + } + None => { + debug!("assemble_unboxed_candidates: closure_kind not yet known"); + candidates.vec.push(ClosureCandidate); + } + } + } + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); + candidates.ambiguous = true; + } + _ => {} + } + + Ok(()) + } + + /// Implements one of the `Fn()` family for a fn pointer. + fn assemble_fn_pointer_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + // We provide impl of all fn traits for fn pointers. + if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() { + return Ok(()); + } + + // Okay to skip binder because what we are inspecting doesn't involve bound regions. + let self_ty = *obligation.self_ty().skip_binder(); + match self_ty.kind { + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_fn_pointer_candidates: ambiguous self-type"); + candidates.ambiguous = true; // Could wind up being a fn() type. + } + // Provide an impl, but only for suitable `fn` pointers. + ty::FnDef(..) | ty::FnPtr(_) => { + if let ty::FnSig { + unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + c_variadic: false, + .. + } = self_ty.fn_sig(self.tcx()).skip_binder() + { + candidates.vec.push(FnPointerCandidate); + } + } + _ => {} + } + + Ok(()) + } + + /// Searches for impls that might apply to `obligation`. + fn assemble_candidates_from_impls( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + debug!("assemble_candidates_from_impls(obligation={:?})", obligation); + + self.tcx().for_each_relevant_impl( + obligation.predicate.def_id(), + obligation.predicate.skip_binder().trait_ref.self_ty(), + |impl_def_id| { + self.infcx.probe(|snapshot| { + if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) { + candidates.vec.push(ImplCandidate(impl_def_id)); + } + }); + }, + ); + + Ok(()) + } + + fn assemble_candidates_from_auto_impls( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + // Okay to skip binder here because the tests we do below do not involve bound regions. + let self_ty = *obligation.self_ty().skip_binder(); + debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty); + + let def_id = obligation.predicate.def_id(); + + if self.tcx().trait_is_auto(def_id) { + match self_ty.kind { + ty::Dynamic(..) => { + // For object types, we don't know what the closed + // over types are. This means we conservatively + // say nothing; a candidate may be added by + // `assemble_candidates_from_object_ty`. + } + ty::Foreign(..) => { + // Since the contents of foreign types is unknown, + // we don't add any `..` impl. Default traits could + // still be provided by a manual implementation for + // this trait and type. + } + ty::Param(..) | ty::Projection(..) => { + // In these cases, we don't know what the actual + // type is. Therefore, we cannot break it down + // into its constituent types. So we don't + // consider the `..` impl but instead just add no + // candidates: this means that typeck will only + // succeed if there is another reason to believe + // that this obligation holds. That could be a + // where-clause or, in the case of an object type, + // it could be that the object type lists the + // trait (e.g., `Foo+Send : Send`). See + // `compile-fail/typeck-default-trait-impl-send-param.rs` + // for an example of a test case that exercises + // this path. + } + ty::Infer(ty::TyVar(_)) => { + // The auto impl might apply; we don't know. + candidates.ambiguous = true; + } + ty::Generator(_, _, movability) + if self.tcx().lang_items().unpin_trait() == Some(def_id) => + { + match movability { + hir::Movability::Static => { + // Immovable generators are never `Unpin`, so + // suppress the normal auto-impl candidate for it. + } + hir::Movability::Movable => { + // Movable generators are always `Unpin`, so add an + // unconditional builtin candidate. + candidates.vec.push(BuiltinCandidate { has_nested: false }); + } + } + } + + _ => candidates.vec.push(AutoImplCandidate(def_id)), + } + } + + Ok(()) + } + + /// Searches for impls that might apply to `obligation`. + fn assemble_candidates_from_object_ty( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + debug!( + "assemble_candidates_from_object_ty(self_ty={:?})", + obligation.self_ty().skip_binder() + ); + + self.infcx.probe(|_snapshot| { + // The code below doesn't care about regions, and the + // self-ty here doesn't escape this probe, so just erase + // any LBR. + let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty()); + let poly_trait_ref = match self_ty.kind { + ty::Dynamic(ref data, ..) => { + if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { + debug!( + "assemble_candidates_from_object_ty: matched builtin bound, \ + pushing candidate" + ); + candidates.vec.push(BuiltinObjectCandidate); + return; + } + + if let Some(principal) = data.principal() { + if !self.infcx.tcx.features().object_safe_for_dispatch { + principal.with_self_ty(self.tcx(), self_ty) + } else if self.tcx().is_object_safe(principal.def_id()) { + principal.with_self_ty(self.tcx(), self_ty) + } else { + return; + } + } else { + // Only auto trait bounds exist. + return; + } + } + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_candidates_from_object_ty: ambiguous"); + candidates.ambiguous = true; // could wind up being an object type + return; + } + _ => return, + }; + + debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref); + + // Count only those upcast versions that match the trait-ref + // we are looking for. Specifically, do not only check for the + // correct trait, but also the correct type parameters. + // For example, we may be trying to upcast `Foo` to `Bar`, + // but `Foo` is declared as `trait Foo: Bar`. + let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref) + .filter(|upcast_trait_ref| { + self.infcx + .probe(|_| self.match_poly_trait_ref(obligation, *upcast_trait_ref).is_ok()) + }) + .count(); + + if upcast_trait_refs > 1 { + // Can be upcast in many ways; need more type information. + candidates.ambiguous = true; + } else if upcast_trait_refs == 1 { + candidates.vec.push(ObjectCandidate); + } + }) + } + + /// Searches for unsizing that might apply to `obligation`. + fn assemble_candidates_for_unsizing( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + // We currently never consider higher-ranked obligations e.g. + // `for<'a> &'a T: Unsize` to be implemented. This is not + // because they are a priori invalid, and we could potentially add support + // for them later, it's just that there isn't really a strong need for it. + // A `T: Unsize` obligation is always used as part of a `T: CoerceUnsize` + // impl, and those are generally applied to concrete types. + // + // That said, one might try to write a fn with a where clause like + // for<'a> Foo<'a, T>: Unsize> + // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`. + // Still, you'd be more likely to write that where clause as + // T: Trait + // so it seems ok if we (conservatively) fail to accept that `Unsize` + // obligation above. Should be possible to extend this in the future. + let source = match obligation.self_ty().no_bound_vars() { + Some(t) => t, + None => { + // Don't add any candidates if there are bound regions. + return; + } + }; + let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); + + debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); + + let may_apply = match (&source.kind, &target.kind) { + // Trait+Kx+'a -> Trait+Ky+'b (upcasts). + (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { + // Upcasts permit two things: + // + // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo` + // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b` + // + // Note that neither of these changes requires any + // change at runtime. Eventually this will be + // generalized. + // + // We always upcast when we can because of reason + // #2 (region bounds). + data_a.principal_def_id() == data_b.principal_def_id() + && data_b + .auto_traits() + // All of a's auto traits need to be in b's auto traits. + .all(|b| data_a.auto_traits().any(|a| a == b)) + } + + // `T` -> `Trait` + (_, &ty::Dynamic(..)) => true, + + // Ambiguous handling is below `T` -> `Trait`, because inference + // variables can still implement `Unsize` and nested + // obligations will have the final say (likely deferred). + (&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => { + debug!("assemble_candidates_for_unsizing: ambiguous"); + candidates.ambiguous = true; + false + } + + // `[T; n]` -> `[T]` + (&ty::Array(..), &ty::Slice(_)) => true, + + // `Struct` -> `Struct` + (&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => { + def_id_a == def_id_b + } + + // `(.., T)` -> `(.., U)` + (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(), + + _ => false, + }; + + if may_apply { + candidates.vec.push(BuiltinUnsizeCandidate); + } + } + + fn assemble_candidates_for_trait_alias( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + // Okay to skip binder here because the tests we do below do not involve bound regions. + let self_ty = *obligation.self_ty().skip_binder(); + debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty); + + let def_id = obligation.predicate.def_id(); + + if self.tcx().is_trait_alias(def_id) { + candidates.vec.push(TraitAliasCandidate(def_id)); + } + + Ok(()) + } + + /////////////////////////////////////////////////////////////////////////// + // WINNOW + // + // Winnowing is the process of attempting to resolve ambiguity by + // probing further. During the winnowing process, we unify all + // type variables and then we also attempt to evaluate recursive + // bounds to see if they are satisfied. + + /// Returns `true` if `victim` should be dropped in favor of + /// `other`. Generally speaking we will drop duplicate + /// candidates and prefer where-clause candidates. + /// + /// See the comment for "SelectionCandidate" for more details. + fn candidate_should_be_dropped_in_favor_of( + &mut self, + victim: &EvaluatedCandidate<'tcx>, + other: &EvaluatedCandidate<'tcx>, + needs_infer: bool, + ) -> bool { + if victim.candidate == other.candidate { + return true; + } + + // Check if a bound would previously have been removed when normalizing + // the param_env so that it can be given the lowest priority. See + // #50825 for the motivation for this. + let is_global = + |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions(); + + match other.candidate { + // Prefer `BuiltinCandidate { has_nested: false }` to anything else. + // This is a fix for #53123 and prevents winnowing from accidentally extending the + // lifetime of a variable. + BuiltinCandidate { has_nested: false } => true, + ParamCandidate(ref cand) => match victim.candidate { + AutoImplCandidate(..) => { + bug!( + "default implementations shouldn't be recorded \ + when there are other valid candidates" + ); + } + // Prefer `BuiltinCandidate { has_nested: false }` to anything else. + // This is a fix for #53123 and prevents winnowing from accidentally extending the + // lifetime of a variable. + BuiltinCandidate { has_nested: false } => false, + ImplCandidate(..) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | BuiltinCandidate { .. } + | TraitAliasCandidate(..) => { + // Global bounds from the where clause should be ignored + // here (see issue #50825). Otherwise, we have a where + // clause so don't go around looking for impls. + !is_global(cand) + } + ObjectCandidate | ProjectionCandidate => { + // Arbitrarily give param candidates priority + // over projection and object candidates. + !is_global(cand) + } + ParamCandidate(..) => false, + }, + ObjectCandidate | ProjectionCandidate => match victim.candidate { + AutoImplCandidate(..) => { + bug!( + "default implementations shouldn't be recorded \ + when there are other valid candidates" + ); + } + // Prefer `BuiltinCandidate { has_nested: false }` to anything else. + // This is a fix for #53123 and prevents winnowing from accidentally extending the + // lifetime of a variable. + BuiltinCandidate { has_nested: false } => false, + ImplCandidate(..) + | ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | BuiltinCandidate { .. } + | TraitAliasCandidate(..) => true, + ObjectCandidate | ProjectionCandidate => { + // Arbitrarily give param candidates priority + // over projection and object candidates. + true + } + ParamCandidate(ref cand) => is_global(cand), + }, + ImplCandidate(other_def) => { + // See if we can toss out `victim` based on specialization. + // This requires us to know *for sure* that the `other` impl applies + // i.e., `EvaluatedToOk`. + if other.evaluation.must_apply_modulo_regions() { + match victim.candidate { + ImplCandidate(victim_def) => { + let tcx = self.tcx(); + if tcx.specializes((other_def, victim_def)) { + return true; + } + return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) { + Some(ty::ImplOverlapKind::Permitted { marker: true }) => { + // Subtle: If the predicate we are evaluating has inference + // variables, do *not* allow discarding candidates due to + // marker trait impls. + // + // Without this restriction, we could end up accidentally + // constrainting inference variables based on an arbitrarily + // chosen trait impl. + // + // Imagine we have the following code: + // + // ```rust + // #[marker] trait MyTrait {} + // impl MyTrait for u8 {} + // impl MyTrait for bool {} + // ``` + // + // And we are evaluating the predicate `<_#0t as MyTrait>`. + // + // During selection, we will end up with one candidate for each + // impl of `MyTrait`. If we were to discard one impl in favor + // of the other, we would be left with one candidate, causing + // us to "successfully" select the predicate, unifying + // _#0t with (for example) `u8`. + // + // However, we have no reason to believe that this unification + // is correct - we've essentially just picked an arbitrary + // *possibility* for _#0t, and required that this be the *only* + // possibility. + // + // Eventually, we will either: + // 1) Unify all inference variables in the predicate through + // some other means (e.g. type-checking of a function). We will + // then be in a position to drop marker trait candidates + // without constraining inference variables (since there are + // none left to constrin) + // 2) Be left with some unconstrained inference variables. We + // will then correctly report an inference error, since the + // existence of multiple marker trait impls tells us nothing + // about which one should actually apply. + !needs_infer + } + Some(_) => true, + None => false, + }; + } + ParamCandidate(ref cand) => { + // Prefer the impl to a global where clause candidate. + return is_global(cand); + } + _ => (), + } + } + + false + } + ClosureCandidate + | GeneratorCandidate + | FnPointerCandidate + | BuiltinObjectCandidate + | BuiltinUnsizeCandidate + | BuiltinCandidate { has_nested: true } => { + match victim.candidate { + ParamCandidate(ref cand) => { + // Prefer these to a global where-clause bound + // (see issue #50825). + is_global(cand) && other.evaluation.must_apply_modulo_regions() + } + _ => false, + } + } + _ => false, + } + } + + /////////////////////////////////////////////////////////////////////////// + // BUILTIN BOUNDS + // + // These cover the traits that are built-in to the language + // itself: `Copy`, `Clone` and `Sized`. + + fn assemble_builtin_bound_candidates( + &mut self, + conditions: BuiltinImplConditions<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) -> Result<(), SelectionError<'tcx>> { + match conditions { + BuiltinImplConditions::Where(nested) => { + debug!("builtin_bound: nested={:?}", nested); + candidates + .vec + .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() }); + } + BuiltinImplConditions::None => {} + BuiltinImplConditions::Ambiguous => { + debug!("assemble_builtin_bound_candidates: ambiguous builtin"); + candidates.ambiguous = true; + } + } + + Ok(()) + } + + fn sized_conditions( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> BuiltinImplConditions<'tcx> { + use self::BuiltinImplConditions::{Ambiguous, None, Where}; + + // NOTE: binder moved to (*) + let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); + + match self_ty.kind { + ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::RawPtr(..) + | ty::Char + | ty::Ref(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Array(..) + | ty::Closure(..) + | ty::Never + | ty::Error => { + // safe for everything + Where(ty::Binder::dummy(Vec::new())) + } + + ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None, + + ty::Tuple(tys) => { + Where(ty::Binder::bind(tys.last().into_iter().map(|k| k.expect_ty()).collect())) + } + + ty::Adt(def, substs) => { + let sized_crit = def.sized_constraint(self.tcx()); + // (*) binder moved here + Where(ty::Binder::bind( + sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect(), + )) + } + + ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None, + ty::Infer(ty::TyVar(_)) => Ambiguous, + + ty::UnnormalizedProjection(..) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_)) + | ty::Infer(ty::FreshIntTy(_)) + | ty::Infer(ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); + } + } + } + + fn copy_clone_conditions( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> BuiltinImplConditions<'tcx> { + // NOTE: binder moved to (*) + let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); + + use self::BuiltinImplConditions::{Ambiguous, None, Where}; + + match self_ty.kind { + ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Error => Where(ty::Binder::dummy(Vec::new())), + + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, hir::Mutability::Not) => { + // Implementations provided in libcore + None + } + + ty::Dynamic(..) + | ty::Str + | ty::Slice(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Foreign(..) + | ty::Ref(_, _, hir::Mutability::Mut) => None, + + ty::Array(element_ty, _) => { + // (*) binder moved here + Where(ty::Binder::bind(vec![element_ty])) + } + + ty::Tuple(tys) => { + // (*) binder moved here + Where(ty::Binder::bind(tys.iter().map(|k| k.expect_ty()).collect())) + } + + ty::Closure(def_id, substs) => { + // (*) binder moved here + Where(ty::Binder::bind(substs.as_closure().upvar_tys(def_id, self.tcx()).collect())) + } + + ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => { + // Fallback to whatever user-defined impls exist in this case. + None + } + + ty::Infer(ty::TyVar(_)) => { + // Unbound type variable. Might or might not have + // applicable impls and so forth, depending on what + // those type variables wind up being bound to. + Ambiguous + } + + ty::UnnormalizedProjection(..) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_)) + | ty::Infer(ty::FreshIntTy(_)) + | ty::Infer(ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); + } + } + } + + /// For default impls, we need to break apart a type into its + /// "constituent types" -- meaning, the types that it contains. + /// + /// Here are some (simple) examples: + /// + /// ``` + /// (i32, u32) -> [i32, u32] + /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32] + /// Bar where struct Bar { x: T, y: u32 } -> [i32, u32] + /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] + /// ``` + fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { + match t.kind { + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Str + | ty::Error + | ty::Infer(ty::IntVar(_)) + | ty::Infer(ty::FloatVar(_)) + | ty::Never + | ty::Char => Vec::new(), + + ty::UnnormalizedProjection(..) + | ty::Placeholder(..) + | ty::Dynamic(..) + | ty::Param(..) + | ty::Foreign(..) + | ty::Projection(..) + | ty::Bound(..) + | ty::Infer(ty::TyVar(_)) + | ty::Infer(ty::FreshTy(_)) + | ty::Infer(ty::FreshIntTy(_)) + | ty::Infer(ty::FreshFloatTy(_)) => { + bug!("asked to assemble constituent types of unexpected type: {:?}", t); + } + + ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { + vec![element_ty] + } + + ty::Array(element_ty, _) | ty::Slice(element_ty) => vec![element_ty], + + ty::Tuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + tys.iter().map(|k| k.expect_ty()).collect() + } + + ty::Closure(def_id, ref substs) => { + substs.as_closure().upvar_tys(def_id, self.tcx()).collect() + } + + ty::Generator(def_id, ref substs, _) => { + let witness = substs.as_generator().witness(def_id, self.tcx()); + substs + .as_generator() + .upvar_tys(def_id, self.tcx()) + .chain(iter::once(witness)) + .collect() + } + + ty::GeneratorWitness(types) => { + // This is sound because no regions in the witness can refer to + // the binder outside the witness. So we'll effectivly reuse + // the implicit binder around the witness. + types.skip_binder().to_vec() + } + + // For `PhantomData`, we pass `T`. + ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(), + + ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect(), + + ty::Opaque(def_id, substs) => { + // We can resolve the `impl Trait` to its concrete type, + // which enforces a DAG between the functions requiring + // the auto trait bounds in question. + vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)] + } + } + } + + fn collect_predicates_for_types( + &mut self, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + recursion_depth: usize, + trait_def_id: DefId, + types: ty::Binder>>, + ) -> Vec> { + // Because the types were potentially derived from + // higher-ranked obligations they may reference late-bound + // regions. For example, `for<'a> Foo<&'a int> : Copy` would + // yield a type like `for<'a> &'a int`. In general, we + // maintain the invariant that we never manipulate bound + // regions, so we have to process these bound regions somehow. + // + // The strategy is to: + // + // 1. Instantiate those regions to placeholder regions (e.g., + // `for<'a> &'a int` becomes `&0 int`. + // 2. Produce something like `&'0 int : Copy` + // 3. Re-bind the regions back to `for<'a> &'a int : Copy` + + types + .skip_binder() + .iter() + .flat_map(|ty| { + // binder moved -\ + let ty: ty::Binder> = ty::Binder::bind(ty); // <----/ + + self.infcx.commit_unconditionally(|_| { + let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty); + let Normalized { value: normalized_ty, mut obligations } = + project::normalize_with_depth( + self, + param_env, + cause.clone(), + recursion_depth, + &skol_ty, + ); + let skol_obligation = predicate_for_trait_def( + self.tcx(), + param_env, + cause.clone(), + trait_def_id, + recursion_depth, + normalized_ty, + &[], + ); + obligations.push(skol_obligation); + obligations + }) + }) + .collect() + } + + /////////////////////////////////////////////////////////////////////////// + // CONFIRMATION + // + // Confirmation unifies the output type parameters of the trait + // with the values found in the obligation, possibly yielding a + // type error. See the [rustc dev guide] for more details. + // + // [rustc dev guide]: + // https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation + + fn confirm_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + candidate: SelectionCandidate<'tcx>, + ) -> Result, SelectionError<'tcx>> { + debug!("confirm_candidate({:?}, {:?})", obligation, candidate); + + match candidate { + BuiltinCandidate { has_nested } => { + let data = self.confirm_builtin_candidate(obligation, has_nested); + Ok(VtableBuiltin(data)) + } + + ParamCandidate(param) => { + let obligations = self.confirm_param_candidate(obligation, param); + Ok(VtableParam(obligations)) + } + + ImplCandidate(impl_def_id) => { + Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id))) + } + + AutoImplCandidate(trait_def_id) => { + let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); + Ok(VtableAutoImpl(data)) + } + + ProjectionCandidate => { + self.confirm_projection_candidate(obligation); + Ok(VtableParam(Vec::new())) + } + + ClosureCandidate => { + let vtable_closure = self.confirm_closure_candidate(obligation)?; + Ok(VtableClosure(vtable_closure)) + } + + GeneratorCandidate => { + let vtable_generator = self.confirm_generator_candidate(obligation)?; + Ok(VtableGenerator(vtable_generator)) + } + + FnPointerCandidate => { + let data = self.confirm_fn_pointer_candidate(obligation)?; + Ok(VtableFnPointer(data)) + } + + TraitAliasCandidate(alias_def_id) => { + let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); + Ok(VtableTraitAlias(data)) + } + + ObjectCandidate => { + let data = self.confirm_object_candidate(obligation); + Ok(VtableObject(data)) + } + + BuiltinObjectCandidate => { + // This indicates something like `Trait + Send: Send`. In this case, we know that + // this holds because that's what the object type is telling us, and there's really + // no additional obligations to prove and no types in particular to unify, etc. + Ok(VtableParam(Vec::new())) + } + + BuiltinUnsizeCandidate => { + let data = self.confirm_builtin_unsize_candidate(obligation)?; + Ok(VtableBuiltin(data)) + } + } + } + + fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { + self.infcx.commit_unconditionally(|snapshot| { + let result = + self.match_projection_obligation_against_definition_bounds(obligation, snapshot); + assert!(result); + }) + } + + fn confirm_param_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + param: ty::PolyTraitRef<'tcx>, + ) -> Vec> { + debug!("confirm_param_candidate({:?},{:?})", obligation, param); + + // During evaluation, we already checked that this + // where-clause trait-ref could be unified with the obligation + // trait-ref. Repeat that unification now without any + // transactional boundary; it should not fail. + match self.match_where_clause_trait_ref(obligation, param.clone()) { + Ok(obligations) => obligations, + Err(()) => { + bug!( + "Where clause `{:?}` was applicable to `{:?}` but now is not", + param, + obligation + ); + } + } + } + + fn confirm_builtin_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + has_nested: bool, + ) -> VtableBuiltinData> { + debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested); + + let lang_items = self.tcx().lang_items(); + let obligations = if has_nested { + let trait_def = obligation.predicate.def_id(); + let conditions = if Some(trait_def) == lang_items.sized_trait() { + self.sized_conditions(obligation) + } else if Some(trait_def) == lang_items.copy_trait() { + self.copy_clone_conditions(obligation) + } else if Some(trait_def) == lang_items.clone_trait() { + self.copy_clone_conditions(obligation) + } else { + bug!("unexpected builtin trait {:?}", trait_def) + }; + let nested = match conditions { + BuiltinImplConditions::Where(nested) => nested, + _ => bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation), + }; + + let cause = obligation.derived_cause(BuiltinDerivedObligation); + self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def, + nested, + ) + } else { + vec![] + }; + + debug!("confirm_builtin_candidate: obligations={:?}", obligations); + + VtableBuiltinData { nested: obligations } + } + + /// This handles the case where a `auto trait Foo` impl is being used. + /// The idea is that the impl applies to `X : Foo` if the following conditions are met: + /// + /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds + /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. + fn confirm_auto_impl_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId, + ) -> VtableAutoImplData> { + debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id); + + let types = obligation.predicate.map_bound(|inner| { + let self_ty = self.infcx.shallow_resolve(inner.self_ty()); + self.constituent_types_for_ty(self_ty) + }); + self.vtable_auto_impl(obligation, trait_def_id, types) + } + + /// See `confirm_auto_impl_candidate`. + fn vtable_auto_impl( + &mut self, + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId, + nested: ty::Binder>>, + ) -> VtableAutoImplData> { + debug!("vtable_auto_impl: nested={:?}", nested); + + let cause = obligation.derived_cause(BuiltinDerivedObligation); + let mut obligations = self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def_id, + nested, + ); + + let trait_obligations: Vec> = + self.infcx.commit_unconditionally(|_| { + let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); + let (trait_ref, _) = + self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref); + let cause = obligation.derived_cause(ImplDerivedObligation); + self.impl_or_trait_obligations( + cause, + obligation.recursion_depth + 1, + obligation.param_env, + trait_def_id, + &trait_ref.substs, + ) + }); + + // Adds the predicates from the trait. Note that this contains a `Self: Trait` + // predicate as usual. It won't have any effect since auto traits are coinductive. + obligations.extend(trait_obligations); + + debug!("vtable_auto_impl: obligations={:?}", obligations); + + VtableAutoImplData { trait_def_id, nested: obligations } + } + + fn confirm_impl_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + impl_def_id: DefId, + ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { + debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id); + + // First, create the substitutions by matching the impl again, + // this time not in a probe. + self.infcx.commit_unconditionally(|snapshot| { + let substs = self.rematch_impl(impl_def_id, obligation, snapshot); + debug!("confirm_impl_candidate: substs={:?}", substs); + let cause = obligation.derived_cause(ImplDerivedObligation); + self.vtable_impl( + impl_def_id, + substs, + cause, + obligation.recursion_depth + 1, + obligation.param_env, + ) + }) + } + + fn vtable_impl( + &mut self, + impl_def_id: DefId, + mut substs: Normalized<'tcx, SubstsRef<'tcx>>, + cause: ObligationCause<'tcx>, + recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, + ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { + debug!( + "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})", + impl_def_id, substs, recursion_depth, + ); + + let mut impl_obligations = self.impl_or_trait_obligations( + cause, + recursion_depth, + param_env, + impl_def_id, + &substs.value, + ); + + debug!( + "vtable_impl: impl_def_id={:?} impl_obligations={:?}", + impl_def_id, impl_obligations + ); + + // Because of RFC447, the impl-trait-ref and obligations + // are sufficient to determine the impl substs, without + // relying on projections in the impl-trait-ref. + // + // e.g., `impl> Foo<::T> for V` + impl_obligations.append(&mut substs.obligations); + + VtableImplData { impl_def_id, substs: substs.value, nested: impl_obligations } + } + + fn confirm_object_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> VtableObjectData<'tcx, PredicateObligation<'tcx>> { + debug!("confirm_object_candidate({:?})", obligation); + + // FIXME(nmatsakis) skipping binder here seems wrong -- we should + // probably flatten the binder from the obligation and the binder + // from the object. Have to try to make a broken test case that + // results. + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let poly_trait_ref = match self_ty.kind { + ty::Dynamic(ref data, ..) => data + .principal() + .unwrap_or_else(|| { + span_bug!(obligation.cause.span, "object candidate with no principal") + }) + .with_self_ty(self.tcx(), self_ty), + _ => span_bug!(obligation.cause.span, "object candidate with non-object"), + }; + + let mut upcast_trait_ref = None; + let mut nested = vec![]; + let vtable_base; + + { + let tcx = self.tcx(); + + // We want to find the first supertrait in the list of + // supertraits that we can unify with, and do that + // unification. We know that there is exactly one in the list + // where we can unify, because otherwise select would have + // reported an ambiguity. (When we do find a match, also + // record it for later.) + let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(|&t| { + match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) { + Ok(obligations) => { + upcast_trait_ref = Some(t); + nested.extend(obligations); + false + } + Err(_) => true, + } + }); + + // Additionally, for each of the non-matching predicates that + // we pass over, we sum up the set of number of vtable + // entries, so that we can compute the offset for the selected + // trait. + vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum(); + } + + VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested } + } + + fn confirm_fn_pointer_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + debug!("confirm_fn_pointer_candidate({:?})", obligation); + + // Okay to skip binder; it is reintroduced below. + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let sig = self_ty.fn_sig(self.tcx()); + let trait_ref = closure_trait_ref_and_return_type( + self.tcx(), + obligation.predicate.def_id(), + self_ty, + sig, + util::TupleArgumentsFlag::Yes, + ) + .map_bound(|(trait_ref, _)| trait_ref); + + let Normalized { value: trait_ref, obligations } = project::normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &trait_ref, + ); + + self.confirm_poly_trait_refs( + obligation.cause.clone(), + obligation.param_env, + obligation.predicate.to_poly_trait_ref(), + trait_ref, + )?; + Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations }) + } + + fn confirm_trait_alias_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + alias_def_id: DefId, + ) -> VtableTraitAliasData<'tcx, PredicateObligation<'tcx>> { + debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id); + + self.infcx.commit_unconditionally(|_| { + let (predicate, _) = + self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); + let trait_ref = predicate.trait_ref; + let trait_def_id = trait_ref.def_id; + let substs = trait_ref.substs; + + let trait_obligations = self.impl_or_trait_obligations( + obligation.cause.clone(), + obligation.recursion_depth, + obligation.param_env, + trait_def_id, + &substs, + ); + + debug!( + "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}", + trait_def_id, trait_obligations + ); + + VtableTraitAliasData { alias_def_id, substs: substs, nested: trait_obligations } + }) + } + + fn confirm_generator_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + // Okay to skip binder because the substs on generator types never + // touch bound regions, they just capture the in-scope + // type/region parameters. + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let (generator_def_id, substs) = match self_ty.kind { + ty::Generator(id, substs, _) => (id, substs), + _ => bug!("closure candidate for non-closure {:?}", obligation), + }; + + debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs); + + let trait_ref = self.generator_trait_ref_unnormalized(obligation, generator_def_id, substs); + let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &trait_ref, + ); + + debug!( + "confirm_generator_candidate(generator_def_id={:?}, \ + trait_ref={:?}, obligations={:?})", + generator_def_id, trait_ref, obligations + ); + + obligations.extend(self.confirm_poly_trait_refs( + obligation.cause.clone(), + obligation.param_env, + obligation.predicate.to_poly_trait_ref(), + trait_ref, + )?); + + Ok(VtableGeneratorData { generator_def_id, substs, nested: obligations }) + } + + fn confirm_closure_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + debug!("confirm_closure_candidate({:?})", obligation); + + let kind = self + .tcx() + .fn_trait_kind_from_lang_item(obligation.predicate.def_id()) + .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation)); + + // Okay to skip binder because the substs on closure types never + // touch bound regions, they just capture the in-scope + // type/region parameters. + let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let (closure_def_id, substs) = match self_ty.kind { + ty::Closure(id, substs) => (id, substs), + _ => bug!("closure candidate for non-closure {:?}", obligation), + }; + + let trait_ref = self.closure_trait_ref_unnormalized(obligation, closure_def_id, substs); + let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &trait_ref, + ); + + debug!( + "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", + closure_def_id, trait_ref, obligations + ); + + obligations.extend(self.confirm_poly_trait_refs( + obligation.cause.clone(), + obligation.param_env, + obligation.predicate.to_poly_trait_ref(), + trait_ref, + )?); + + obligations.push(Obligation::new( + obligation.cause.clone(), + obligation.param_env, + ty::Predicate::ClosureKind(closure_def_id, substs, kind), + )); + + Ok(VtableClosureData { closure_def_id, substs, nested: obligations }) + } + + /// In the case of closure types and fn pointers, + /// we currently treat the input type parameters on the trait as + /// outputs. This means that when we have a match we have only + /// considered the self type, so we have to go back and make sure + /// to relate the argument types too. This is kind of wrong, but + /// since we control the full set of impls, also not that wrong, + /// and it DOES yield better error messages (since we don't report + /// errors as if there is no applicable impl, but rather report + /// errors are about mismatched argument types. + /// + /// Here is an example. Imagine we have a closure expression + /// and we desugared it so that the type of the expression is + /// `Closure`, and `Closure` expects an int as argument. Then it + /// is "as if" the compiler generated this impl: + /// + /// impl Fn(int) for Closure { ... } + /// + /// Now imagine our obligation is `Fn(usize) for Closure`. So far + /// we have matched the self type `Closure`. At this point we'll + /// compare the `int` to `usize` and generate an error. + /// + /// Note that this checking occurs *after* the impl has selected, + /// because these output type parameters should not affect the + /// selection of the impl. Therefore, if there is a mismatch, we + /// report an error to the user. + fn confirm_poly_trait_refs( + &mut self, + obligation_cause: ObligationCause<'tcx>, + obligation_param_env: ty::ParamEnv<'tcx>, + obligation_trait_ref: ty::PolyTraitRef<'tcx>, + expected_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + self.infcx + .at(&obligation_cause, obligation_param_env) + .sup(obligation_trait_ref, expected_trait_ref) + .map(|InferOk { obligations, .. }| obligations) + .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) + } + + fn confirm_builtin_unsize_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + let tcx = self.tcx(); + + // `assemble_candidates_for_unsizing` should ensure there are no late-bound + // regions here. See the comment there for more details. + let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); + let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); + let target = self.infcx.shallow_resolve(target); + + debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target); + + let mut nested = vec![]; + match (&source.kind, &target.kind) { + // Trait+Kx+'a -> Trait+Ky+'b (upcasts). + (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { + // See `assemble_candidates_for_unsizing` for more info. + let existential_predicates = data_a.map_bound(|data_a| { + let iter = data_a + .principal() + .map(|x| ty::ExistentialPredicate::Trait(x)) + .into_iter() + .chain( + data_a + .projection_bounds() + .map(|x| ty::ExistentialPredicate::Projection(x)), + ) + .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait)); + tcx.mk_existential_predicates(iter) + }); + let source_trait = tcx.mk_dynamic(existential_predicates, r_b); + + // Require that the traits involved in this upcast are **equal**; + // only the **lifetime bound** is changed. + // + // FIXME: This condition is arguably too strong -- it would + // suffice for the source trait to be a *subtype* of the target + // trait. In particular, changing from something like + // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be + // permitted. And, indeed, in the in commit + // 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this + // condition was loosened. However, when the leak check was + // added back, using subtype here actually guides the coercion + // code in such a way that it accepts `old-lub-glb-object.rs`. + // This is probably a good thing, but I've modified this to `.eq` + // because I want to continue rejecting that test (as we have + // done for quite some time) before we are firmly comfortable + // with what our behavior should be there. -nikomatsakis + let InferOk { obligations, .. } = self + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(target, source_trait) // FIXME -- see below + .map_err(|_| Unimplemented)?; + nested.extend(obligations); + + // Register one obligation for 'a: 'b. + let cause = ObligationCause::new( + obligation.cause.span, + obligation.cause.body_id, + ObjectCastObligation(target), + ); + let outlives = ty::OutlivesPredicate(r_a, r_b); + nested.push(Obligation::with_depth( + cause, + obligation.recursion_depth + 1, + obligation.param_env, + ty::Binder::bind(outlives).to_predicate(), + )); + } + + // `T` -> `Trait` + (_, &ty::Dynamic(ref data, r)) => { + let mut object_dids = data.auto_traits().chain(data.principal_def_id()); + if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { + return Err(TraitNotObjectSafe(did)); + } + + let cause = ObligationCause::new( + obligation.cause.span, + obligation.cause.body_id, + ObjectCastObligation(target), + ); + + let predicate_to_obligation = |predicate| { + Obligation::with_depth( + cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + predicate, + ) + }; + + // Create obligations: + // - Casting `T` to `Trait` + // - For all the various builtin bounds attached to the object cast. (In other + // words, if the object type is `Foo + Send`, this would create an obligation for + // the `Send` check.) + // - Projection predicates + nested.extend( + data.iter().map(|predicate| { + predicate_to_obligation(predicate.with_self_ty(tcx, source)) + }), + ); + + // We can only make objects from sized types. + let tr = ty::TraitRef::new( + tcx.require_lang_item(lang_items::SizedTraitLangItem, None), + tcx.mk_substs_trait(source, &[]), + ); + nested.push(predicate_to_obligation(tr.without_const().to_predicate())); + + // If the type is `Foo + 'a`, ensure that the type + // being cast to `Foo + 'a` outlives `'a`: + let outlives = ty::OutlivesPredicate(source, r); + nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate())); + } + + // `[T; n]` -> `[T]` + (&ty::Array(a, _), &ty::Slice(b)) => { + let InferOk { obligations, .. } = self + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(b, a) + .map_err(|_| Unimplemented)?; + nested.extend(obligations); + } + + // `Struct` -> `Struct` + (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { + let fields = + def.all_fields().map(|field| tcx.type_of(field.did)).collect::>(); + + // The last field of the structure has to exist and contain type parameters. + let field = if let Some(&field) = fields.last() { + field + } else { + return Err(Unimplemented); + }; + let mut ty_params = GrowableBitSet::new_empty(); + let mut found = false; + for ty in field.walk() { + if let ty::Param(p) = ty.kind { + ty_params.insert(p.index as usize); + found = true; + } + } + if !found { + return Err(Unimplemented); + } + + // Replace type parameters used in unsizing with + // Error and ensure they do not affect any other fields. + // This could be checked after type collection for any struct + // with a potentially unsized trailing field. + let params = substs_a + .iter() + .enumerate() + .map(|(i, &k)| if ty_params.contains(i) { tcx.types.err.into() } else { k }); + let substs = tcx.mk_substs(params); + for &ty in fields.split_last().unwrap().1 { + if ty.subst(tcx, substs).references_error() { + return Err(Unimplemented); + } + } + + // Extract `Field` and `Field` from `Struct` and `Struct`. + let inner_source = field.subst(tcx, substs_a); + let inner_target = field.subst(tcx, substs_b); + + // Check that the source struct with the target's + // unsized parameters is equal to the target. + let params = substs_a.iter().enumerate().map(|(i, &k)| { + if ty_params.contains(i) { substs_b.type_at(i).into() } else { k } + }); + let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); + let InferOk { obligations, .. } = self + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(target, new_struct) + .map_err(|_| Unimplemented)?; + nested.extend(obligations); + + // Construct the nested `Field: Unsize>` predicate. + nested.push(predicate_for_trait_def( + tcx, + obligation.param_env, + obligation.cause.clone(), + obligation.predicate.def_id(), + obligation.recursion_depth + 1, + inner_source, + &[inner_target.into()], + )); + } + + // `(.., T)` -> `(.., U)` + (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => { + assert_eq!(tys_a.len(), tys_b.len()); + + // The last field of the tuple has to exist. + let (&a_last, a_mid) = if let Some(x) = tys_a.split_last() { + x + } else { + return Err(Unimplemented); + }; + let &b_last = tys_b.last().unwrap(); + + // Check that the source tuple with the target's + // last element is equal to the target. + let new_tuple = tcx.mk_tup( + a_mid.iter().map(|k| k.expect_ty()).chain(iter::once(b_last.expect_ty())), + ); + let InferOk { obligations, .. } = self + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(target, new_tuple) + .map_err(|_| Unimplemented)?; + nested.extend(obligations); + + // Construct the nested `T: Unsize` predicate. + nested.push(predicate_for_trait_def( + tcx, + obligation.param_env, + obligation.cause.clone(), + obligation.predicate.def_id(), + obligation.recursion_depth + 1, + a_last.expect_ty(), + &[b_last], + )); + } + + _ => bug!(), + }; + + Ok(VtableBuiltinData { nested }) + } + + /////////////////////////////////////////////////////////////////////////// + // Matching + // + // Matching is a common path used for both evaluation and + // confirmation. It basically unifies types that appear in impls + // and traits. This does affect the surrounding environment; + // therefore, when used during evaluation, match routines must be + // run inside of a `probe()` so that their side-effects are + // contained. + + fn rematch_impl( + &mut self, + impl_def_id: DefId, + obligation: &TraitObligation<'tcx>, + snapshot: &CombinedSnapshot<'_, 'tcx>, + ) -> Normalized<'tcx, SubstsRef<'tcx>> { + match self.match_impl(impl_def_id, obligation, snapshot) { + Ok(substs) => substs, + Err(()) => { + bug!( + "Impl {:?} was matchable against {:?} but now is not", + impl_def_id, + obligation + ); + } + } + } + + fn match_impl( + &mut self, + impl_def_id: DefId, + obligation: &TraitObligation<'tcx>, + snapshot: &CombinedSnapshot<'_, 'tcx>, + ) -> Result>, ()> { + let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); + + // Before we create the substitutions and everything, first + // consider a "quick reject". This avoids creating more types + // and so forth that we need to. + if self.fast_reject_trait_refs(obligation, &impl_trait_ref) { + return Err(()); + } + + let (skol_obligation, placeholder_map) = + self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); + let skol_obligation_trait_ref = skol_obligation.trait_ref; + + let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); + + let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); + + let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = + project::normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &impl_trait_ref, + ); + + debug!( + "match_impl(impl_def_id={:?}, obligation={:?}, \ + impl_trait_ref={:?}, skol_obligation_trait_ref={:?})", + impl_def_id, obligation, impl_trait_ref, skol_obligation_trait_ref + ); + + let InferOk { obligations, .. } = self + .infcx + .at(&obligation.cause, obligation.param_env) + .eq(skol_obligation_trait_ref, impl_trait_ref) + .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?; + nested_obligations.extend(obligations); + + if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) { + debug!("match_impl: failed leak check due to `{}`", e); + return Err(()); + } + + if !self.intercrate + && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation + { + debug!("match_impl: reservation impls only apply in intercrate mode"); + return Err(()); + } + + debug!("match_impl: success impl_substs={:?}", impl_substs); + Ok(Normalized { value: impl_substs, obligations: nested_obligations }) + } + + fn fast_reject_trait_refs( + &mut self, + obligation: &TraitObligation<'_>, + impl_trait_ref: &ty::TraitRef<'_>, + ) -> bool { + // We can avoid creating type variables and doing the full + // substitution if we find that any of the input types, when + // simplified, do not match. + + obligation.predicate.skip_binder().input_types().zip(impl_trait_ref.input_types()).any( + |(obligation_ty, impl_ty)| { + let simplified_obligation_ty = + fast_reject::simplify_type(self.tcx(), obligation_ty, true); + let simplified_impl_ty = fast_reject::simplify_type(self.tcx(), impl_ty, false); + + simplified_obligation_ty.is_some() + && simplified_impl_ty.is_some() + && simplified_obligation_ty != simplified_impl_ty + }, + ) + } + + /// Normalize `where_clause_trait_ref` and try to match it against + /// `obligation`. If successful, return any predicates that + /// result from the normalization. Normalization is necessary + /// because where-clauses are stored in the parameter environment + /// unnormalized. + fn match_where_clause_trait_ref( + &mut self, + obligation: &TraitObligation<'tcx>, + where_clause_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result>, ()> { + self.match_poly_trait_ref(obligation, where_clause_trait_ref) + } + + /// Returns `Ok` if `poly_trait_ref` being true implies that the + /// obligation is satisfied. + fn match_poly_trait_ref( + &mut self, + obligation: &TraitObligation<'tcx>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Result>, ()> { + debug!( + "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}", + obligation, poly_trait_ref + ); + + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) + .map(|InferOk { obligations, .. }| obligations) + .map_err(|_| ()) + } + + /////////////////////////////////////////////////////////////////////////// + // Miscellany + + fn match_fresh_trait_refs( + &self, + previous: &ty::PolyTraitRef<'tcx>, + current: &ty::PolyTraitRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> bool { + let mut matcher = ty::_match::Match::new(self.tcx(), param_env); + matcher.relate(previous, current).is_ok() + } + + fn push_stack<'o>( + &mut self, + previous_stack: TraitObligationStackList<'o, 'tcx>, + obligation: &'o TraitObligation<'tcx>, + ) -> TraitObligationStack<'o, 'tcx> { + let fresh_trait_ref = + obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener); + + let dfn = previous_stack.cache.next_dfn(); + let depth = previous_stack.depth() + 1; + TraitObligationStack { + obligation, + fresh_trait_ref, + reached_depth: Cell::new(depth), + previous: previous_stack, + dfn, + depth, + } + } + + fn closure_trait_ref_unnormalized( + &mut self, + obligation: &TraitObligation<'tcx>, + closure_def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> ty::PolyTraitRef<'tcx> { + debug!( + "closure_trait_ref_unnormalized(obligation={:?}, closure_def_id={:?}, substs={:?})", + obligation, closure_def_id, substs, + ); + let closure_type = self.infcx.closure_sig(closure_def_id, substs); + + debug!("closure_trait_ref_unnormalized: closure_type = {:?}", closure_type); + + // (1) Feels icky to skip the binder here, but OTOH we know + // that the self-type is an unboxed closure type and hence is + // in fact unparameterized (or at least does not reference any + // regions bound in the obligation). Still probably some + // refactoring could make this nicer. + closure_trait_ref_and_return_type( + self.tcx(), + obligation.predicate.def_id(), + obligation.predicate.skip_binder().self_ty(), // (1) + closure_type, + util::TupleArgumentsFlag::No, + ) + .map_bound(|(trait_ref, _)| trait_ref) + } + + fn generator_trait_ref_unnormalized( + &mut self, + obligation: &TraitObligation<'tcx>, + closure_def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> ty::PolyTraitRef<'tcx> { + let gen_sig = substs.as_generator().poly_sig(closure_def_id, self.tcx()); + + // (1) Feels icky to skip the binder here, but OTOH we know + // that the self-type is an generator type and hence is + // in fact unparameterized (or at least does not reference any + // regions bound in the obligation). Still probably some + // refactoring could make this nicer. + + super::util::generator_trait_ref_and_outputs( + self.tcx(), + obligation.predicate.def_id(), + obligation.predicate.skip_binder().self_ty(), // (1) + gen_sig, + ) + .map_bound(|(trait_ref, ..)| trait_ref) + } + + /// Returns the obligations that are implied by instantiating an + /// impl or trait. The obligations are substituted and fully + /// normalized. This is used when confirming an impl or default + /// impl. + fn impl_or_trait_obligations( + &mut self, + cause: ObligationCause<'tcx>, + recursion_depth: usize, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, // of impl or trait + substs: SubstsRef<'tcx>, // for impl or trait + ) -> Vec> { + debug!("impl_or_trait_obligations(def_id={:?})", def_id); + let tcx = self.tcx(); + + // To allow for one-pass evaluation of the nested obligation, + // each predicate must be preceded by the obligations required + // to normalize it. + // for example, if we have: + // impl, V: Iterator> Foo for V + // the impl will have the following predicates: + // ::Item = U, + // U: Iterator, U: Sized, + // V: Iterator, V: Sized, + // ::Item: Copy + // When we substitute, say, `V => IntoIter, U => $0`, the last + // obligation will normalize to `<$0 as Iterator>::Item = $1` and + // `$1: Copy`, so we must ensure the obligations are emitted in + // that order. + let predicates = tcx.predicates_of(def_id); + assert_eq!(predicates.parent, None); + let mut obligations = Vec::with_capacity(predicates.predicates.len()); + for (predicate, _) in predicates.predicates { + let predicate = normalize_with_depth_to( + self, + param_env, + cause.clone(), + recursion_depth, + &predicate.subst(tcx, substs), + &mut obligations, + ); + obligations.push(Obligation { + cause: cause.clone(), + recursion_depth, + param_env, + predicate, + }); + } + + // We are performing deduplication here to avoid exponential blowups + // (#38528) from happening, but the real cause of the duplication is + // unknown. What we know is that the deduplication avoids exponential + // amount of predicates being propagated when processing deeply nested + // types. + // + // This code is hot enough that it's worth avoiding the allocation + // required for the FxHashSet when possible. Special-casing lengths 0, + // 1 and 2 covers roughly 75-80% of the cases. + if obligations.len() <= 1 { + // No possibility of duplicates. + } else if obligations.len() == 2 { + // Only two elements. Drop the second if they are equal. + if obligations[0] == obligations[1] { + obligations.truncate(1); + } + } else { + // Three or more elements. Use a general deduplication process. + let mut seen = FxHashSet::default(); + obligations.retain(|i| seen.insert(i.clone())); + } + + obligations + } +} + +trait TraitObligationExt<'tcx> { + fn derived_cause( + &self, + variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + ) -> ObligationCause<'tcx>; +} + +impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> { + #[allow(unused_comparisons)] + fn derived_cause( + &self, + variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + ) -> ObligationCause<'tcx> { + /*! + * Creates a cause for obligations that are derived from + * `obligation` by a recursive search (e.g., for a builtin + * bound, or eventually a `auto trait Foo`). If `obligation` + * is itself a derived obligation, this is just a clone, but + * otherwise we create a "derived obligation" cause so as to + * keep track of the original root obligation for error + * reporting. + */ + + let obligation = self; + + // NOTE(flaper87): As of now, it keeps track of the whole error + // chain. Ideally, we should have a way to configure this either + // by using -Z verbose or just a CLI argument. + let derived_cause = DerivedObligationCause { + parent_trait_ref: obligation.predicate.to_poly_trait_ref(), + parent_code: Rc::new(obligation.cause.code.clone()), + }; + let derived_code = variant(derived_cause); + ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) + } +} + +impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { + fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> { + TraitObligationStackList::with(self) + } + + fn cache(&self) -> &'o ProvisionalEvaluationCache<'tcx> { + self.previous.cache + } + + fn iter(&'o self) -> TraitObligationStackList<'o, 'tcx> { + self.list() + } + + /// Indicates that attempting to evaluate this stack entry + /// required accessing something from the stack at depth `reached_depth`. + fn update_reached_depth(&self, reached_depth: usize) { + assert!( + self.depth > reached_depth, + "invoked `update_reached_depth` with something under this stack: \ + self.depth={} reached_depth={}", + self.depth, + reached_depth, + ); + debug!("update_reached_depth(reached_depth={})", reached_depth); + let mut p = self; + while reached_depth < p.depth { + debug!("update_reached_depth: marking {:?} as cycle participant", p.fresh_trait_ref); + p.reached_depth.set(p.reached_depth.get().min(reached_depth)); + p = p.previous.head.unwrap(); + } + } +} + +/// The "provisional evaluation cache" is used to store intermediate cache results +/// when solving auto traits. Auto traits are unusual in that they can support +/// cycles. So, for example, a "proof tree" like this would be ok: +/// +/// - `Foo: Send` :- +/// - `Bar: Send` :- +/// - `Foo: Send` -- cycle, but ok +/// - `Baz: Send` +/// +/// Here, to prove `Foo: Send`, we have to prove `Bar: Send` and +/// `Baz: Send`. Proving `Bar: Send` in turn required `Foo: Send`. +/// For non-auto traits, this cycle would be an error, but for auto traits (because +/// they are coinductive) it is considered ok. +/// +/// However, there is a complication: at the point where we have +/// "proven" `Bar: Send`, we have in fact only proven it +/// *provisionally*. In particular, we proved that `Bar: Send` +/// *under the assumption* that `Foo: Send`. But what if we later +/// find out this assumption is wrong? Specifically, we could +/// encounter some kind of error proving `Baz: Send`. In that case, +/// `Bar: Send` didn't turn out to be true. +/// +/// In Issue #60010, we found a bug in rustc where it would cache +/// these intermediate results. This was fixed in #60444 by disabling +/// *all* caching for things involved in a cycle -- in our example, +/// that would mean we don't cache that `Bar: Send`. But this led +/// to large slowdowns. +/// +/// Specifically, imagine this scenario, where proving `Baz: Send` +/// first requires proving `Bar: Send` (which is true: +/// +/// - `Foo: Send` :- +/// - `Bar: Send` :- +/// - `Foo: Send` -- cycle, but ok +/// - `Baz: Send` +/// - `Bar: Send` -- would be nice for this to be a cache hit! +/// - `*const T: Send` -- but what if we later encounter an error? +/// +/// The *provisional evaluation cache* resolves this issue. It stores +/// cache results that we've proven but which were involved in a cycle +/// in some way. We track the minimal stack depth (i.e., the +/// farthest from the top of the stack) that we are dependent on. +/// The idea is that the cache results within are all valid -- so long as +/// none of the nodes in between the current node and the node at that minimum +/// depth result in an error (in which case the cached results are just thrown away). +/// +/// During evaluation, we consult this provisional cache and rely on +/// it. Accessing a cached value is considered equivalent to accessing +/// a result at `reached_depth`, so it marks the *current* solution as +/// provisional as well. If an error is encountered, we toss out any +/// provisional results added from the subtree that encountered the +/// error. When we pop the node at `reached_depth` from the stack, we +/// can commit all the things that remain in the provisional cache. +struct ProvisionalEvaluationCache<'tcx> { + /// next "depth first number" to issue -- just a counter + dfn: Cell, + + /// Stores the "coldest" depth (bottom of stack) reached by any of + /// the evaluation entries. The idea here is that all things in the provisional + /// cache are always dependent on *something* that is colder in the stack: + /// therefore, if we add a new entry that is dependent on something *colder still*, + /// we have to modify the depth for all entries at once. + /// + /// Example: + /// + /// Imagine we have a stack `A B C D E` (with `E` being the top of + /// the stack). We cache something with depth 2, which means that + /// it was dependent on C. Then we pop E but go on and process a + /// new node F: A B C D F. Now F adds something to the cache with + /// depth 1, meaning it is dependent on B. Our original cache + /// entry is also dependent on B, because there is a path from E + /// to C and then from C to F and from F to B. + reached_depth: Cell, + + /// Map from cache key to the provisionally evaluated thing. + /// The cache entries contain the result but also the DFN in which they + /// were added. The DFN is used to clear out values on failure. + /// + /// Imagine we have a stack like: + /// + /// - `A B C` and we add a cache for the result of C (DFN 2) + /// - Then we have a stack `A B D` where `D` has DFN 3 + /// - We try to solve D by evaluating E: `A B D E` (DFN 4) + /// - `E` generates various cache entries which have cyclic dependices on `B` + /// - `A B D E F` and so forth + /// - the DFN of `F` for example would be 5 + /// - then we determine that `E` is in error -- we will then clear + /// all cache values whose DFN is >= 4 -- in this case, that + /// means the cached value for `F`. + map: RefCell, ProvisionalEvaluation>>, +} + +/// A cache value for the provisional cache: contains the depth-first +/// number (DFN) and result. +#[derive(Copy, Clone, Debug)] +struct ProvisionalEvaluation { + from_dfn: usize, + result: EvaluationResult, +} + +impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> { + fn default() -> Self { + Self { + dfn: Cell::new(0), + reached_depth: Cell::new(std::usize::MAX), + map: Default::default(), + } + } +} + +impl<'tcx> ProvisionalEvaluationCache<'tcx> { + /// Get the next DFN in sequence (basically a counter). + fn next_dfn(&self) -> usize { + let result = self.dfn.get(); + self.dfn.set(result + 1); + result + } + + /// Check the provisional cache for any result for + /// `fresh_trait_ref`. If there is a hit, then you must consider + /// it an access to the stack slots at depth + /// `self.current_reached_depth()` and above. + fn get_provisional(&self, fresh_trait_ref: ty::PolyTraitRef<'tcx>) -> Option { + debug!( + "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}", + fresh_trait_ref, + self.map.borrow().get(&fresh_trait_ref), + self.reached_depth.get(), + ); + Some(self.map.borrow().get(&fresh_trait_ref)?.result) + } + + /// Current value of the `reached_depth` counter -- all the + /// provisional cache entries are dependent on the item at this + /// depth. + fn current_reached_depth(&self) -> usize { + self.reached_depth.get() + } + + /// Insert a provisional result into the cache. The result came + /// from the node with the given DFN. It accessed a minimum depth + /// of `reached_depth` to compute. It evaluated `fresh_trait_ref` + /// and resulted in `result`. + fn insert_provisional( + &self, + from_dfn: usize, + reached_depth: usize, + fresh_trait_ref: ty::PolyTraitRef<'tcx>, + result: EvaluationResult, + ) { + debug!( + "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})", + from_dfn, reached_depth, fresh_trait_ref, result, + ); + let r_d = self.reached_depth.get(); + self.reached_depth.set(r_d.min(reached_depth)); + + debug!("insert_provisional: reached_depth={:?}", self.reached_depth.get()); + + self.map.borrow_mut().insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, result }); + } + + /// Invoked when the node with dfn `dfn` does not get a successful + /// result. This will clear out any provisional cache entries + /// that were added since `dfn` was created. This is because the + /// provisional entries are things which must assume that the + /// things on the stack at the time of their creation succeeded -- + /// since the failing node is presently at the top of the stack, + /// these provisional entries must either depend on it or some + /// ancestor of it. + fn on_failure(&self, dfn: usize) { + debug!("on_failure(dfn={:?})", dfn,); + self.map.borrow_mut().retain(|key, eval| { + if !eval.from_dfn >= dfn { + debug!("on_failure: removing {:?}", key); + false + } else { + true + } + }); + } + + /// Invoked when the node at depth `depth` completed without + /// depending on anything higher in the stack (if that completion + /// was a failure, then `on_failure` should have been invoked + /// already). The callback `op` will be invoked for each + /// provisional entry that we can now confirm. + fn on_completion( + &self, + depth: usize, + mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult), + ) { + debug!("on_completion(depth={}, reached_depth={})", depth, self.reached_depth.get(),); + + if self.reached_depth.get() < depth { + debug!("on_completion: did not yet reach depth to complete"); + return; + } + + for (fresh_trait_ref, eval) in self.map.borrow_mut().drain() { + debug!("on_completion: fresh_trait_ref={:?} eval={:?}", fresh_trait_ref, eval,); + + op(fresh_trait_ref, eval.result); + } + + self.reached_depth.set(std::usize::MAX); + } +} + +#[derive(Copy, Clone)] +struct TraitObligationStackList<'o, 'tcx> { + cache: &'o ProvisionalEvaluationCache<'tcx>, + head: Option<&'o TraitObligationStack<'o, 'tcx>>, +} + +impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> { + fn empty(cache: &'o ProvisionalEvaluationCache<'tcx>) -> TraitObligationStackList<'o, 'tcx> { + TraitObligationStackList { cache, head: None } + } + + fn with(r: &'o TraitObligationStack<'o, 'tcx>) -> TraitObligationStackList<'o, 'tcx> { + TraitObligationStackList { cache: r.cache(), head: Some(r) } + } + + fn head(&self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { + self.head + } + + fn depth(&self) -> usize { + if let Some(head) = self.head { head.depth } else { 0 } + } +} + +impl<'o, 'tcx> Iterator for TraitObligationStackList<'o, 'tcx> { + type Item = &'o TraitObligationStack<'o, 'tcx>; + + fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { + match self.head { + Some(o) => { + *self = o.previous; + Some(o) + } + None => None, + } + } +} + +impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "TraitObligationStack({:?})", self.obligation) + } +} diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc_trait_selection/traits/specialize/mod.rs similarity index 91% rename from src/librustc/traits/specialize/mod.rs rename to src/librustc_trait_selection/traits/specialize/mod.rs index 7c93a35158b..b763851b86e 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc_trait_selection/traits/specialize/mod.rs @@ -4,19 +4,20 @@ //! At the moment, this implementation support only the simple "chain" rule: //! If any two impls overlap, one must be a strict subset of the other. //! -//! See the [rustc guide] for a bit more detail on how specialization +//! See the [rustc dev guide] for a bit more detail on how specialization //! fits together with the rest of the trait machinery. //! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/specialization.html +//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html pub mod specialization_graph; +use specialization_graph::GraphExt; -use crate::infer::{InferCtxt, InferOk}; +use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine}; -use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use crate::ty::{self, TyCtxt, TypeFoldable}; use rustc::lint::LintDiagnosticBuilder; +use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; +use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir::def_id::DefId; @@ -129,24 +130,27 @@ pub fn find_associated_item<'tcx>( let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); let trait_def = tcx.trait_def(trait_def_id); - let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id); - match ancestors.leaf_def(tcx, item.ident, item.kind) { - Some(node_item) => { - let substs = tcx.infer_ctxt().enter(|infcx| { - let param_env = param_env.with_reveal_all(); - let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); - let substs = translate_substs( - &infcx, - param_env, - impl_data.impl_def_id, - substs, - node_item.node, - ); - infcx.tcx.erase_regions(&substs) - }); - (node_item.item.def_id, substs) + if let Ok(ancestors) = trait_def.ancestors(tcx, impl_data.impl_def_id) { + match ancestors.leaf_def(tcx, item.ident, item.kind) { + Some(node_item) => { + let substs = tcx.infer_ctxt().enter(|infcx| { + let param_env = param_env.with_reveal_all(); + let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); + let substs = translate_substs( + &infcx, + param_env, + impl_data.impl_def_id, + substs, + node_item.node, + ); + infcx.tcx.erase_regions(&substs) + }); + (node_item.item.def_id, substs) + } + None => bug!("{:?} not found in {:?}", item, impl_data.impl_def_id), } - None => bug!("{:?} not found in {:?}", item, impl_data.impl_def_id), + } else { + (item.def_id, substs) } } @@ -160,7 +164,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, // The feature gate should prevent introducing new specializations, but not // taking advantage of upstream ones. - if !tcx.features().specialization && (impl1_def_id.is_local() || impl2_def_id.is_local()) { + let features = tcx.features(); + let specialization_enabled = features.specialization || features.min_specialization; + if !specialization_enabled && (impl1_def_id.is_local() || impl2_def_id.is_local()) { return false; } @@ -379,6 +385,7 @@ pub(super) fn specialization_graph_provider( match used_to_be_allowed { None => { + sg.has_errored = true; let err = struct_span_err!(tcx.sess, impl_span, E0119, ""); decorate(LintDiagnosticBuilder::new(err)); } @@ -412,12 +419,7 @@ pub(super) fn specialization_graph_provider( fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option { use std::fmt::Write; - let trait_ref = if let Some(tr) = tcx.impl_trait_ref(impl_def_id) { - tr - } else { - return None; - }; - + let trait_ref = tcx.impl_trait_ref(impl_def_id)?; let mut w = "impl".to_owned(); let substs = InternalSubsts::identity_for_item(tcx, impl_def_id); diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc_trait_selection/traits/specialize/specialization_graph.rs similarity index 87% rename from src/librustc/traits/specialize/specialization_graph.rs rename to src/librustc_trait_selection/traits/specialize/specialization_graph.rs index e09bcdcbc62..17d4a22b9dd 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc_trait_selection/traits/specialize/specialization_graph.rs @@ -5,7 +5,7 @@ use rustc::ty::fast_reject::{self, SimplifiedType}; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc_hir::def_id::DefId; -pub use rustc::traits::types::specialization_graph::*; +pub use rustc::traits::specialization_graph::*; #[derive(Copy, Clone, Debug)] pub enum FutureCompatOverlapErrorKind { @@ -31,7 +31,19 @@ enum Inserted { ShouldRecurseOn(DefId), } -impl<'tcx> Children { +trait ChildrenExt { + fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId); + fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId); + + fn insert( + &mut self, + tcx: TyCtxt<'tcx>, + impl_def_id: DefId, + simplified_self: Option, + ) -> Result; +} + +impl ChildrenExt for Children { /// Insert an impl into this set of children without comparing to any existing impls. fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); @@ -76,8 +88,8 @@ impl<'tcx> Children { debug!("insert(impl_def_id={:?}, simplified_self={:?})", impl_def_id, simplified_self,); let possible_siblings = match simplified_self { - Some(st) => PotentialSiblings::Filtered(self.filtered(st)), - None => PotentialSiblings::Unfiltered(self.iter()), + Some(st) => PotentialSiblings::Filtered(filtered_children(self, st)), + None => PotentialSiblings::Unfiltered(iter_children(self)), }; for possible_sibling in possible_siblings { @@ -199,16 +211,19 @@ impl<'tcx> Children { self.insert_blindly(tcx, impl_def_id); Ok(Inserted::BecameNewSibling(last_lint)) } +} - fn iter(&mut self) -> impl Iterator + '_ { - let nonblanket = self.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter()); - self.blanket_impls.iter().chain(nonblanket).cloned() - } +fn iter_children(children: &mut Children) -> impl Iterator + '_ { + let nonblanket = children.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter()); + children.blanket_impls.iter().chain(nonblanket).cloned() +} - fn filtered(&mut self, st: SimplifiedType) -> impl Iterator + '_ { - let nonblanket = self.nonblanket_impls.entry(st).or_default().iter(); - self.blanket_impls.iter().chain(nonblanket).cloned() - } +fn filtered_children( + children: &mut Children, + st: SimplifiedType, +) -> impl Iterator + '_ { + let nonblanket = children.nonblanket_impls.entry(st).or_default().iter(); + children.blanket_impls.iter().chain(nonblanket).cloned() } // A custom iterator used by Children::insert @@ -236,11 +251,25 @@ where } } -impl<'tcx> Graph { +pub trait GraphExt { /// Insert a local impl into the specialization graph. If an existing impl /// conflicts with it (has overlap, but neither specializes the other), /// information about the area of overlap is returned in the `Err`. - pub fn insert( + fn insert( + &mut self, + tcx: TyCtxt<'tcx>, + impl_def_id: DefId, + ) -> Result, OverlapError>; + + /// Insert cached metadata mapping from a child impl back to its parent. + fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId); +} + +impl GraphExt for Graph { + /// Insert a local impl into the specialization graph. If an existing impl + /// conflicts with it (has overlap, but neither specializes the other), + /// information about the area of overlap is returned in the `Err`. + fn insert( &mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId, @@ -337,7 +366,7 @@ impl<'tcx> Graph { } /// Insert cached metadata mapping from a child impl back to its parent. - pub fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId) { + fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId) { if self.parent.insert(child, parent).is_some() { bug!( "When recording an impl from the crate store, information about its parent \ diff --git a/src/librustc/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs similarity index 97% rename from src/librustc/traits/structural_match.rs rename to src/librustc_trait_selection/traits/structural_match.rs index b2c3c23b4e3..60682f58129 100644 --- a/src/librustc/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -1,9 +1,8 @@ -use crate::ty::fold::{TypeFoldable, TypeVisitor}; -use crate::ty::{self, AdtDef, Ty, TyCtxt}; +use crate::infer::{InferCtxt, TyCtxtInferExt}; +use crate::traits::ObligationCause; +use crate::traits::{self, ConstPatternStructural, TraitEngine}; -use rustc::infer::InferCtxt; -use rustc::traits::ObligationCause; -use rustc::traits::{self, ConstPatternStructural, TraitEngine}; +use rustc::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_span::Span; diff --git a/src/librustc/traits/util.rs b/src/librustc_trait_selection/traits/util.rs similarity index 98% rename from src/librustc/traits/util.rs rename to src/librustc_trait_selection/traits/util.rs index d4c3518260c..cd4595e76cc 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc_trait_selection/traits/util.rs @@ -1,10 +1,11 @@ use rustc_errors::DiagnosticBuilder; use rustc_span::Span; +use smallvec::smallvec; use smallvec::SmallVec; -use crate::ty::outlives::Component; -use crate::ty::subst::{GenericArg, Subst, SubstsRef}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc::ty::outlives::Component; +use rustc::ty::subst::{GenericArg, Subst, SubstsRef}; +use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -54,7 +55,7 @@ struct PredicateSet<'tcx> { impl PredicateSet<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Self { - Self { tcx: tcx, set: Default::default() } + Self { tcx, set: Default::default() } } fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool { @@ -585,7 +586,7 @@ pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<' let mut entries = 0; // Count number of methods and add them to the total offset. // Skip over associated types and constants. - for trait_item in tcx.associated_items(trait_ref.def_id()) { + for trait_item in tcx.associated_items(trait_ref.def_id()).in_definition_order() { if trait_item.kind == ty::AssocKind::Method { entries += 1; } @@ -605,7 +606,7 @@ pub fn get_vtable_index_of_object_method( // add them to the total offset. // Skip over associated types and constants. let mut entries = object.vtable_base; - for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()) { + for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() { if trait_item.def_id == method_def_id { // The item with the ID we were given really ought to be a method. assert_eq!(trait_item.kind, ty::AssocKind::Method); diff --git a/src/librustc/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs similarity index 97% rename from src/librustc/traits/wf.rs rename to src/librustc_trait_selection/traits/wf.rs index 48721ec04e7..b69c5bdce2a 100644 --- a/src/librustc/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -1,9 +1,9 @@ -use crate::infer::opaque_types::required_region_bounds; use crate::infer::InferCtxt; -use crate::middle::lang_items; +use crate::opaque_types::required_region_bounds; use crate::traits::{self, AssocTypeBoundData}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; +use rustc::middle::lang_items; +use rustc::ty::subst::SubstsRef; +use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_span::symbol::{kw, Ident}; @@ -232,10 +232,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // found type `()` if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) { let trait_assoc_item = tcx.associated_item(proj.projection_def_id()); - if let Some(impl_item) = items - .iter() - .filter(|item| item.ident == trait_assoc_item.ident) - .next() + if let Some(impl_item) = + items.iter().find(|item| item.ident == trait_assoc_item.ident) { cause.span = impl_item.span; cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData { @@ -285,13 +283,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { { if let Some((impl_item, trait_assoc_item)) = trait_assoc_items .iter() - .filter(|i| i.def_id == *item_def_id) - .next() + .find(|i| i.def_id == *item_def_id) .and_then(|trait_assoc_item| { items .iter() - .filter(|i| i.ident == trait_assoc_item.ident) - .next() + .find(|i| i.ident == trait_assoc_item.ident) .map(|impl_item| (impl_item, trait_assoc_item)) }) { @@ -318,7 +314,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { }; if let Elaborate::All = elaborate { - let trait_assoc_items = tcx.associated_items(trait_ref.def_id); + // FIXME: Make `extend_cause_with_original_assoc_item_obligation` take an iterator + // instead of a slice. + let trait_assoc_items: Vec<_> = + tcx.associated_items(trait_ref.def_id).in_definition_order().copied().collect(); let predicates = obligations.iter().map(|obligation| obligation.predicate).collect(); let implied_obligations = traits::elaborate_predicates(tcx, predicates); @@ -327,7 +326,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { extend_cause_with_original_assoc_item_obligation( &mut cause, &pred, - trait_assoc_items, + &*trait_assoc_items, ); traits::Obligation::new(cause, param_env, pred) }); diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml index 2cb25e63f83..5e33efb1cf9 100644 --- a/src/librustc_traits/Cargo.toml +++ b/src/librustc_traits/Cargo.toml @@ -15,7 +15,8 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_hir = { path = "../librustc_hir" } rustc_macros = { path = "../librustc_macros" } rustc_target = { path = "../librustc_target" } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } -chalk-engine = { version = "0.9.0", default-features=false } smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_infer = { path = "../librustc_infer" } +rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs deleted file mode 100644 index 0b18352df33..00000000000 --- a/src/librustc_traits/chalk_context/mod.rs +++ /dev/null @@ -1,638 +0,0 @@ -mod program_clauses; -mod resolvent_ops; -mod unify; - -use chalk_engine::fallible::Fallible; -use chalk_engine::forest::Forest; -use chalk_engine::{context, hh::HhGoal, DelayedLiteral, ExClause, Literal}; -use rustc::infer::canonical::{ - Canonical, CanonicalVarValues, Certainty, OriginalQueryValues, QueryRegionConstraints, - QueryResponse, -}; -use rustc::infer::{InferCtxt, LateBoundRegionConversionTime}; -use rustc::traits::{ - self, ChalkCanonicalGoal, ChalkContextLift, Clause, DomainGoal, Environment, ExClauseFold, - Goal, GoalKind, InEnvironment, QuantifierKind, -}; -use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use rustc::ty::query::Providers; -use rustc::ty::subst::{GenericArg, GenericArgKind}; -use rustc::ty::{self, TyCtxt}; -use rustc_macros::{Lift, TypeFoldable}; -use rustc_span::DUMMY_SP; - -use std::fmt::{self, Debug}; -use std::marker::PhantomData; - -use self::unify::*; - -#[derive(Copy, Clone, Debug)] -crate struct ChalkArenas<'tcx> { - _phantom: PhantomData<&'tcx ()>, -} - -#[derive(Copy, Clone)] -crate struct ChalkContext<'tcx> { - _arenas: ChalkArenas<'tcx>, - tcx: TyCtxt<'tcx>, -} - -#[derive(Copy, Clone)] -crate struct ChalkInferenceContext<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, -} - -#[derive(Copy, Clone, Debug)] -crate struct UniverseMap; - -crate type RegionConstraint<'tcx> = ty::OutlivesPredicate, ty::Region<'tcx>>; - -#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, Lift)] -crate struct ConstrainedSubst<'tcx> { - subst: CanonicalVarValues<'tcx>, - constraints: Vec>, -} - -impl context::Context for ChalkArenas<'tcx> { - type CanonicalExClause = Canonical<'tcx, ChalkExClause<'tcx>>; - - type CanonicalGoalInEnvironment = Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>; - - // u-canonicalization not yet implemented - type UCanonicalGoalInEnvironment = Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>; - - type CanonicalConstrainedSubst = Canonical<'tcx, ConstrainedSubst<'tcx>>; - - // u-canonicalization not yet implemented - type UniverseMap = UniverseMap; - - type Solution = Canonical<'tcx, QueryResponse<'tcx, ()>>; - - type InferenceNormalizedSubst = CanonicalVarValues<'tcx>; - - type GoalInEnvironment = InEnvironment<'tcx, Goal<'tcx>>; - - type RegionConstraint = RegionConstraint<'tcx>; - - type Substitution = CanonicalVarValues<'tcx>; - - type Environment = Environment<'tcx>; - - type Goal = Goal<'tcx>; - - type DomainGoal = DomainGoal<'tcx>; - - type BindersGoal = ty::Binder>; - - type Parameter = GenericArg<'tcx>; - - type ProgramClause = Clause<'tcx>; - - type ProgramClauses = Vec>; - - type UnificationResult = UnificationResult<'tcx>; - - type Variance = ty::Variance; - - fn goal_in_environment( - env: &Environment<'tcx>, - goal: Goal<'tcx>, - ) -> InEnvironment<'tcx, Goal<'tcx>> { - env.with(goal) - } -} - -impl context::AggregateOps> for ChalkContext<'tcx> { - fn make_solution( - &self, - root_goal: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, - mut simplified_answers: impl context::AnswerStream>, - ) -> Option>> { - use chalk_engine::SimplifiedAnswer; - - debug!("make_solution(root_goal = {:?})", root_goal); - - if simplified_answers.peek_answer().is_none() { - return None; - } - - let SimplifiedAnswer { subst: constrained_subst, ambiguous } = - simplified_answers.next_answer().unwrap(); - - debug!("make_solution: ambiguous flag = {}", ambiguous); - - let ambiguous = simplified_answers.peek_answer().is_some() || ambiguous; - - let solution = constrained_subst.unchecked_map(|cs| match ambiguous { - true => QueryResponse { - var_values: cs.subst.make_identity(self.tcx), - region_constraints: QueryRegionConstraints::default(), - certainty: Certainty::Ambiguous, - value: (), - }, - - false => QueryResponse { - var_values: cs.subst, - region_constraints: QueryRegionConstraints::default(), - - // FIXME: restore this later once we get better at handling regions - // region_constraints: cs.constraints - // .into_iter() - // .map(|c| ty::Binder::bind(c)) - // .collect(), - certainty: Certainty::Proven, - value: (), - }, - }); - - debug!("make_solution: solution = {:?}", solution); - - Some(solution) - } -} - -impl context::ContextOps> for ChalkContext<'tcx> { - /// Returns `true` if this is a coinductive goal: basically proving that an auto trait - /// is implemented or proving that a trait reference is well-formed. - fn is_coinductive(&self, goal: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>) -> bool { - use rustc::traits::{WellFormed, WhereClause}; - - let mut goal = goal.value.goal; - loop { - match goal { - GoalKind::DomainGoal(domain_goal) => match domain_goal { - DomainGoal::WellFormed(WellFormed::Trait(..)) => return true, - DomainGoal::Holds(WhereClause::Implemented(trait_predicate)) => { - return self.tcx.trait_is_auto(trait_predicate.def_id()); - } - _ => return false, - }, - - GoalKind::Quantified(_, bound_goal) => goal = *bound_goal.skip_binder(), - _ => return false, - } - } - } - - /// Creates an inference table for processing a new goal and instantiate that goal - /// in that context, returning "all the pieces". - /// - /// More specifically: given a u-canonical goal `arg`, creates a - /// new inference table `T` and populates it with the universes - /// found in `arg`. Then, creates a substitution `S` that maps - /// each bound variable in `arg` to a fresh inference variable - /// from T. Returns: - /// - /// - the table `T`, - /// - the substitution `S`, - /// - the environment and goal found by substitution `S` into `arg`. - fn instantiate_ucanonical_goal( - &self, - arg: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, - op: impl context::WithInstantiatedUCanonicalGoal, Output = R>, - ) -> R { - self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, arg, |ref infcx, arg, subst| { - let chalk_infcx = &mut ChalkInferenceContext { infcx }; - op.with(chalk_infcx, subst, arg.environment, arg.goal) - }) - } - - fn instantiate_ex_clause( - &self, - _num_universes: usize, - arg: &Canonical<'tcx, ChalkExClause<'tcx>>, - op: impl context::WithInstantiatedExClause, Output = R>, - ) -> R { - self.tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &arg.upcast(), |ref infcx, arg, _| { - let chalk_infcx = &mut ChalkInferenceContext { infcx }; - op.with(chalk_infcx, arg) - }) - } - - /// Returns `true` if this solution has no region constraints. - fn empty_constraints(ccs: &Canonical<'tcx, ConstrainedSubst<'tcx>>) -> bool { - ccs.value.constraints.is_empty() - } - - fn inference_normalized_subst_from_ex_clause( - canon_ex_clause: &'a Canonical<'tcx, ChalkExClause<'tcx>>, - ) -> &'a CanonicalVarValues<'tcx> { - &canon_ex_clause.value.subst - } - - fn inference_normalized_subst_from_subst( - canon_subst: &'a Canonical<'tcx, ConstrainedSubst<'tcx>>, - ) -> &'a CanonicalVarValues<'tcx> { - &canon_subst.value.subst - } - - fn canonical( - u_canon: &'a Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, - ) -> &'a Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> { - u_canon - } - - fn is_trivial_substitution( - u_canon: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, - canonical_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>, - ) -> bool { - let subst = &canonical_subst.value.subst; - assert_eq!(u_canon.variables.len(), subst.var_values.len()); - subst.var_values.iter_enumerated().all(|(cvar, kind)| match kind.unpack() { - GenericArgKind::Lifetime(r) => match r { - &ty::ReLateBound(debruijn, br) => { - debug_assert_eq!(debruijn, ty::INNERMOST); - cvar == br.assert_bound_var() - } - _ => false, - }, - GenericArgKind::Type(ty) => match ty.kind { - ty::Bound(debruijn, bound_ty) => { - debug_assert_eq!(debruijn, ty::INNERMOST); - cvar == bound_ty.var - } - _ => false, - }, - GenericArgKind::Const(ct) => match ct.val { - ty::ConstKind::Bound(debruijn, bound_ct) => { - debug_assert_eq!(debruijn, ty::INNERMOST); - cvar == bound_ct - } - _ => false, - }, - }) - } - - fn num_universes(canon: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>) -> usize { - canon.max_universe.index() + 1 - } - - /// Convert a goal G *from* the canonical universes *into* our - /// local universes. This will yield a goal G' that is the same - /// but for the universes of universally quantified names. - fn map_goal_from_canonical( - _map: &UniverseMap, - value: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, - ) -> Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> { - *value // FIXME universe maps not implemented yet - } - - fn map_subst_from_canonical( - _map: &UniverseMap, - value: &Canonical<'tcx, ConstrainedSubst<'tcx>>, - ) -> Canonical<'tcx, ConstrainedSubst<'tcx>> { - value.clone() // FIXME universe maps not implemented yet - } -} - -impl context::InferenceTable, ChalkArenas<'tcx>> - for ChalkInferenceContext<'cx, 'tcx> -{ - fn into_goal(&self, domain_goal: DomainGoal<'tcx>) -> Goal<'tcx> { - self.infcx.tcx.mk_goal(GoalKind::DomainGoal(domain_goal)) - } - - fn cannot_prove(&self) -> Goal<'tcx> { - self.infcx.tcx.mk_goal(GoalKind::CannotProve) - } - - fn into_hh_goal(&mut self, goal: Goal<'tcx>) -> ChalkHhGoal<'tcx> { - match *goal { - GoalKind::Implies(hypotheses, goal) => { - HhGoal::Implies(hypotheses.iter().cloned().collect(), goal) - } - GoalKind::And(left, right) => HhGoal::And(left, right), - GoalKind::Not(subgoal) => HhGoal::Not(subgoal), - GoalKind::DomainGoal(d) => HhGoal::DomainGoal(d), - GoalKind::Quantified(QuantifierKind::Universal, binder) => HhGoal::ForAll(binder), - GoalKind::Quantified(QuantifierKind::Existential, binder) => HhGoal::Exists(binder), - GoalKind::Subtype(a, b) => HhGoal::Unify(ty::Variance::Covariant, a.into(), b.into()), - GoalKind::CannotProve => HhGoal::CannotProve, - } - } - - fn add_clauses( - &mut self, - env: &Environment<'tcx>, - clauses: Vec>, - ) -> Environment<'tcx> { - Environment { - clauses: self - .infcx - .tcx - .mk_clauses(env.clauses.iter().cloned().chain(clauses.into_iter())), - } - } -} - -impl context::TruncateOps, ChalkArenas<'tcx>> - for ChalkInferenceContext<'cx, 'tcx> -{ - fn truncate_goal( - &mut self, - _subgoal: &InEnvironment<'tcx, Goal<'tcx>>, - ) -> Option>> { - None // FIXME we should truncate at some point! - } - - fn truncate_answer( - &mut self, - _subst: &CanonicalVarValues<'tcx>, - ) -> Option> { - None // FIXME we should truncate at some point! - } -} - -impl context::UnificationOps, ChalkArenas<'tcx>> - for ChalkInferenceContext<'cx, 'tcx> -{ - fn program_clauses( - &self, - environment: &Environment<'tcx>, - goal: &DomainGoal<'tcx>, - ) -> Vec> { - self.program_clauses_impl(environment, goal) - } - - fn instantiate_binders_universally(&mut self, arg: &ty::Binder>) -> Goal<'tcx> { - self.infcx.replace_bound_vars_with_placeholders(arg).0 - } - - fn instantiate_binders_existentially(&mut self, arg: &ty::Binder>) -> Goal<'tcx> { - self.infcx - .replace_bound_vars_with_fresh_vars( - DUMMY_SP, - LateBoundRegionConversionTime::HigherRankedType, - arg, - ) - .0 - } - - fn debug_ex_clause(&mut self, value: &'v ChalkExClause<'tcx>) -> Box { - let string = format!("{:?}", self.infcx.resolve_vars_if_possible(value)); - Box::new(string) - } - - fn canonicalize_goal( - &mut self, - value: &InEnvironment<'tcx, Goal<'tcx>>, - ) -> Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>> { - let mut _orig_values = OriginalQueryValues::default(); - self.infcx.canonicalize_query(value, &mut _orig_values) - } - - fn canonicalize_ex_clause( - &mut self, - value: &ChalkExClause<'tcx>, - ) -> Canonical<'tcx, ChalkExClause<'tcx>> { - self.infcx.canonicalize_response(value) - } - - fn canonicalize_constrained_subst( - &mut self, - subst: CanonicalVarValues<'tcx>, - constraints: Vec>, - ) -> Canonical<'tcx, ConstrainedSubst<'tcx>> { - self.infcx.canonicalize_response(&ConstrainedSubst { subst, constraints }) - } - - fn u_canonicalize_goal( - &mut self, - value: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, - ) -> (Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, UniverseMap) { - (*value, UniverseMap) - } - - fn invert_goal( - &mut self, - _value: &InEnvironment<'tcx, Goal<'tcx>>, - ) -> Option>> { - panic!("goal inversion not yet implemented") - } - - fn unify_parameters( - &mut self, - environment: &Environment<'tcx>, - variance: ty::Variance, - a: &GenericArg<'tcx>, - b: &GenericArg<'tcx>, - ) -> Fallible> { - self.infcx.commit_if_ok(|_| { - unify(self.infcx, *environment, variance, a, b) - .map_err(|_| chalk_engine::fallible::NoSolution) - }) - } - - fn sink_answer_subset( - &self, - value: &Canonical<'tcx, ConstrainedSubst<'tcx>>, - ) -> Canonical<'tcx, ConstrainedSubst<'tcx>> { - value.clone() - } - - fn lift_delayed_literal( - &self, - value: DelayedLiteral>, - ) -> DelayedLiteral> { - match self.infcx.tcx.lift(&value) { - Some(literal) => literal, - None => bug!("cannot lift {:?}", value), - } - } - - fn into_ex_clause( - &mut self, - result: UnificationResult<'tcx>, - ex_clause: &mut ChalkExClause<'tcx>, - ) { - into_ex_clause(result, ex_clause); - } -} - -crate fn into_ex_clause(result: UnificationResult<'tcx>, ex_clause: &mut ChalkExClause<'tcx>) { - ex_clause.subgoals.extend(result.goals.into_iter().map(Literal::Positive)); - - // FIXME: restore this later once we get better at handling regions - let _ = result.constraints.len(); // trick `-D dead-code` - // ex_clause.constraints.extend(result.constraints); -} - -type ChalkHhGoal<'tcx> = HhGoal>; - -type ChalkExClause<'tcx> = ExClause>; - -impl Debug for ChalkContext<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ChalkContext") - } -} - -impl Debug for ChalkInferenceContext<'cx, 'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ChalkInferenceContext") - } -} - -impl ChalkContextLift<'tcx> for ChalkArenas<'a> { - type LiftedExClause = ChalkExClause<'tcx>; - type LiftedDelayedLiteral = DelayedLiteral>; - type LiftedLiteral = Literal>; - - fn lift_ex_clause_to_tcx( - ex_clause: &ChalkExClause<'a>, - tcx: TyCtxt<'tcx>, - ) -> Option { - Some(ChalkExClause { - subst: tcx.lift(&ex_clause.subst)?, - delayed_literals: tcx.lift(&ex_clause.delayed_literals)?, - constraints: tcx.lift(&ex_clause.constraints)?, - subgoals: tcx.lift(&ex_clause.subgoals)?, - }) - } - - fn lift_delayed_literal_to_tcx( - literal: &DelayedLiteral>, - tcx: TyCtxt<'tcx>, - ) -> Option { - Some(match literal { - DelayedLiteral::CannotProve(()) => DelayedLiteral::CannotProve(()), - DelayedLiteral::Negative(index) => DelayedLiteral::Negative(*index), - DelayedLiteral::Positive(index, subst) => { - DelayedLiteral::Positive(*index, tcx.lift(subst)?) - } - }) - } - - fn lift_literal_to_tcx( - literal: &Literal>, - tcx: TyCtxt<'tcx>, - ) -> Option { - Some(match literal { - Literal::Negative(goal) => Literal::Negative(tcx.lift(goal)?), - Literal::Positive(goal) => Literal::Positive(tcx.lift(goal)?), - }) - } -} - -impl ExClauseFold<'tcx> for ChalkArenas<'tcx> { - fn fold_ex_clause_with>( - ex_clause: &ChalkExClause<'tcx>, - folder: &mut F, - ) -> ChalkExClause<'tcx> { - ExClause { - subst: ex_clause.subst.fold_with(folder), - delayed_literals: ex_clause.delayed_literals.fold_with(folder), - constraints: ex_clause.constraints.fold_with(folder), - subgoals: ex_clause.subgoals.fold_with(folder), - } - } - - fn visit_ex_clause_with>( - ex_clause: &ExClause, - visitor: &mut V, - ) -> bool { - let ExClause { subst, delayed_literals, constraints, subgoals } = ex_clause; - subst.visit_with(visitor) - || delayed_literals.visit_with(visitor) - || constraints.visit_with(visitor) - || subgoals.visit_with(visitor) - } -} - -trait Upcast<'tcx>: 'tcx { - type Upcasted: 'tcx; - - fn upcast(&self) -> Self::Upcasted; -} - -impl<'tcx> Upcast<'tcx> for DelayedLiteral> { - type Upcasted = DelayedLiteral>; - - fn upcast(&self) -> Self::Upcasted { - match self { - &DelayedLiteral::CannotProve(..) => DelayedLiteral::CannotProve(()), - &DelayedLiteral::Negative(index) => DelayedLiteral::Negative(index), - DelayedLiteral::Positive(index, subst) => { - DelayedLiteral::Positive(*index, subst.clone()) - } - } - } -} - -impl<'tcx> Upcast<'tcx> for Literal> { - type Upcasted = Literal>; - - fn upcast(&self) -> Self::Upcasted { - match self { - &Literal::Negative(goal) => Literal::Negative(goal), - &Literal::Positive(goal) => Literal::Positive(goal), - } - } -} - -impl<'tcx> Upcast<'tcx> for ExClause> { - type Upcasted = ExClause>; - - fn upcast(&self) -> Self::Upcasted { - ExClause { - subst: self.subst.clone(), - delayed_literals: self.delayed_literals.iter().map(|l| l.upcast()).collect(), - constraints: self.constraints.clone(), - subgoals: self.subgoals.iter().map(|g| g.upcast()).collect(), - } - } -} - -impl<'tcx, T> Upcast<'tcx> for Canonical<'tcx, T> -where - T: Upcast<'tcx>, -{ - type Upcasted = Canonical<'tcx, T::Upcasted>; - - fn upcast(&self) -> Self::Upcasted { - Canonical { - max_universe: self.max_universe, - value: self.value.upcast(), - variables: self.variables, - } - } -} - -crate fn provide(p: &mut Providers<'_>) { - *p = Providers { evaluate_goal, ..*p }; -} - -crate fn evaluate_goal<'tcx>( - tcx: TyCtxt<'tcx>, - goal: ChalkCanonicalGoal<'tcx>, -) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> { - use crate::lowering::Lower; - use rustc::traits::WellFormed; - - let goal = goal.unchecked_map(|goal| InEnvironment { - environment: goal.environment, - goal: match goal.goal { - ty::Predicate::WellFormed(ty) => { - tcx.mk_goal(GoalKind::DomainGoal(DomainGoal::WellFormed(WellFormed::Ty(ty)))) - } - - ty::Predicate::Subtype(predicate) => tcx.mk_goal(GoalKind::Quantified( - QuantifierKind::Universal, - predicate.map_bound(|pred| tcx.mk_goal(GoalKind::Subtype(pred.a, pred.b))), - )), - - other => tcx.mk_goal(GoalKind::from_poly_domain_goal(other.lower(), tcx)), - }, - }); - - debug!("evaluate_goal(goal = {:?})", goal); - - let context = ChalkContext { _arenas: ChalkArenas { _phantom: PhantomData }, tcx }; - - let mut forest = Forest::new(context); - let solution = forest.solve(&goal); - - debug!("evaluate_goal: solution = {:?}", solution); - - solution.map(|ok| Ok(&*tcx.arena.alloc(ok))).unwrap_or(Err(traits::query::NoSolution)) -} diff --git a/src/librustc_traits/chalk_context/program_clauses/builtin.rs b/src/librustc_traits/chalk_context/program_clauses/builtin.rs deleted file mode 100644 index 7512cbbd882..00000000000 --- a/src/librustc_traits/chalk_context/program_clauses/builtin.rs +++ /dev/null @@ -1,316 +0,0 @@ -use crate::generic_types; -use crate::lowering::Lower; -use rustc::traits::{Clause, GoalKind, ProgramClause, ProgramClauseCategory}; -use rustc::ty::subst::{GenericArg, InternalSubsts, Subst}; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; - -/// Returns a predicate of the form -/// `Implemented(ty: Trait) :- Implemented(nested: Trait)...` -/// where `Trait` is specified by `trait_def_id`. -fn builtin_impl_clause( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - nested: &[GenericArg<'tcx>], - trait_def_id: DefId, -) -> ProgramClause<'tcx> { - ProgramClause { - goal: ty::TraitPredicate { - trait_ref: ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) }, - } - .lower(), - hypotheses: tcx.mk_goals( - nested - .iter() - .cloned() - .map(|nested_ty| ty::TraitRef { - def_id: trait_def_id, - substs: tcx.mk_substs_trait(nested_ty.expect_ty(), &[]), - }) - .map(|trait_ref| ty::TraitPredicate { trait_ref }) - .map(|pred| GoalKind::DomainGoal(pred.lower())) - .map(|goal_kind| tcx.mk_goal(goal_kind)), - ), - category: ProgramClauseCategory::Other, - } -} - -crate fn assemble_builtin_unsize_impls<'tcx>( - tcx: TyCtxt<'tcx>, - unsize_def_id: DefId, - source: Ty<'tcx>, - target: Ty<'tcx>, - clauses: &mut Vec>, -) { - match (&source.kind, &target.kind) { - (ty::Dynamic(data_a, ..), ty::Dynamic(data_b, ..)) => { - if data_a.principal_def_id() != data_b.principal_def_id() - || data_b.auto_traits().any(|b| data_a.auto_traits().all(|a| a != b)) - { - return; - } - - // FIXME: rules for trait upcast - } - - (_, &ty::Dynamic(..)) => { - // FIXME: basically, we should have something like: - // ``` - // forall { - // Implemented(T: Unsize< for<...> dyn Trait<...> >) :- - // for<...> Implemented(T: Trait<...>). - // } - // ``` - // The question is: how to correctly handle the higher-ranked - // `for<...>` binder in order to have a generic rule? - // (Having generic rules is useful for caching, as we may be able - // to turn this function and others into tcx queries later on). - } - - (ty::Array(_, length), ty::Slice(_)) => { - let ty_param = generic_types::bound(tcx, 0); - let array_ty = tcx.mk_ty(ty::Array(ty_param, length)); - let slice_ty = tcx.mk_ty(ty::Slice(ty_param)); - - // `forall { Implemented([T; N]: Unsize<[T]>). }` - let clause = ProgramClause { - goal: ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: unsize_def_id, - substs: tcx.mk_substs_trait(array_ty, &[slice_ty.into()]), - }, - } - .lower(), - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::Other, - }; - - clauses.push(Clause::ForAll(ty::Binder::bind(clause))); - } - - (ty::Infer(ty::TyVar(_)), _) | (_, ty::Infer(ty::TyVar(_))) => { - // FIXME: ambiguous - } - - (ty::Adt(def_id_a, ..), ty::Adt(def_id_b, ..)) => { - if def_id_a != def_id_b { - return; - } - - // FIXME: rules for struct unsizing - } - - (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => { - if tys_a.len() != tys_b.len() { - return; - } - - // FIXME: rules for tuple unsizing - } - - _ => (), - } -} - -crate fn assemble_builtin_sized_impls<'tcx>( - tcx: TyCtxt<'tcx>, - sized_def_id: DefId, - ty: Ty<'tcx>, - clauses: &mut Vec>, -) { - let mut push_builtin_impl = |ty: Ty<'tcx>, nested: &[GenericArg<'tcx>]| { - let clause = builtin_impl_clause(tcx, ty, nested, sized_def_id); - // Bind innermost bound vars that may exist in `ty` and `nested`. - clauses.push(Clause::ForAll(ty::Binder::bind(clause))); - }; - - match &ty.kind { - // Non parametric primitive types. - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::Error - | ty::Never => push_builtin_impl(ty, &[]), - - // These ones are always `Sized`. - &ty::Array(_, length) => { - push_builtin_impl(tcx.mk_ty(ty::Array(generic_types::bound(tcx, 0), length)), &[]); - } - ty::RawPtr(ptr) => { - push_builtin_impl(generic_types::raw_ptr(tcx, ptr.mutbl), &[]); - } - &ty::Ref(_, _, mutbl) => { - push_builtin_impl(generic_types::ref_ty(tcx, mutbl), &[]); - } - ty::FnPtr(fn_ptr) => { - let fn_ptr = fn_ptr.skip_binder(); - let fn_ptr = generic_types::fn_ptr( - tcx, - fn_ptr.inputs_and_output.len(), - fn_ptr.c_variadic, - fn_ptr.unsafety, - fn_ptr.abi, - ); - push_builtin_impl(fn_ptr, &[]); - } - &ty::FnDef(def_id, ..) => { - push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]); - } - &ty::Closure(def_id, ..) => { - push_builtin_impl(generic_types::closure(tcx, def_id), &[]); - } - &ty::Generator(def_id, ..) => { - push_builtin_impl(generic_types::generator(tcx, def_id), &[]); - } - - // `Sized` if the last type is `Sized` (because else we will get a WF error anyway). - &ty::Tuple(type_list) => { - let type_list = generic_types::type_list(tcx, type_list.len()); - push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &type_list); - } - - // Struct def - ty::Adt(adt_def, _) => { - let substs = InternalSubsts::bound_vars_for_item(tcx, adt_def.did); - let adt = tcx.mk_ty(ty::Adt(adt_def, substs)); - let sized_constraint = adt_def - .sized_constraint(tcx) - .iter() - .map(|ty| GenericArg::from(ty.subst(tcx, substs))) - .collect::>(); - push_builtin_impl(adt, &sized_constraint); - } - - // Artificially trigger an ambiguity by adding two possible types to - // unify against. - ty::Infer(ty::TyVar(_)) => { - push_builtin_impl(tcx.types.i32, &[]); - push_builtin_impl(tcx.types.f32, &[]); - } - - ty::Projection(_projection_ty) => { - // FIXME: add builtin impls from the associated type values found in - // trait impls of `projection_ty.trait_ref(tcx)`. - } - - // The `Sized` bound can only come from the environment. - ty::Param(..) | ty::Placeholder(..) | ty::UnnormalizedProjection(..) => (), - - // Definitely not `Sized`. - ty::Foreign(..) | ty::Str | ty::Slice(..) | ty::Dynamic(..) | ty::Opaque(..) => (), - - ty::Bound(..) - | ty::GeneratorWitness(..) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty), - } -} - -crate fn assemble_builtin_copy_clone_impls<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - ty: Ty<'tcx>, - clauses: &mut Vec>, -) { - let mut push_builtin_impl = |ty: Ty<'tcx>, nested: &[GenericArg<'tcx>]| { - let clause = builtin_impl_clause(tcx, ty, nested, trait_def_id); - // Bind innermost bound vars that may exist in `ty` and `nested`. - clauses.push(Clause::ForAll(ty::Binder::bind(clause))); - }; - - match &ty.kind { - // Implementations provided in libcore. - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::RawPtr(..) - | ty::Never - | ty::Ref(_, _, hir::Mutability::Not) => (), - - // Non parametric primitive types. - ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) | ty::Error => { - push_builtin_impl(ty, &[]) - } - - // These implement `Copy`/`Clone` if their element types do. - &ty::Array(_, length) => { - let element_ty = generic_types::bound(tcx, 0); - push_builtin_impl( - tcx.mk_ty(ty::Array(element_ty, length)), - &[GenericArg::from(element_ty)], - ); - } - &ty::Tuple(type_list) => { - let type_list = generic_types::type_list(tcx, type_list.len()); - push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list); - } - &ty::Closure(def_id, ..) => { - let closure_ty = generic_types::closure(tcx, def_id); - let upvar_tys: Vec<_> = match &closure_ty.kind { - ty::Closure(_, substs) => substs - .as_closure() - .upvar_tys(def_id, tcx) - .map(|ty| GenericArg::from(ty)) - .collect(), - _ => bug!(), - }; - push_builtin_impl(closure_ty, &upvar_tys); - } - - // These ones are always `Clone`. - ty::FnPtr(fn_ptr) => { - let fn_ptr = fn_ptr.skip_binder(); - let fn_ptr = generic_types::fn_ptr( - tcx, - fn_ptr.inputs_and_output.len(), - fn_ptr.c_variadic, - fn_ptr.unsafety, - fn_ptr.abi, - ); - push_builtin_impl(fn_ptr, &[]); - } - &ty::FnDef(def_id, ..) => { - push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]); - } - - // These depend on whatever user-defined impls might exist. - ty::Adt(_, _) => (), - - // Artificially trigger an ambiguity by adding two possible types to - // unify against. - ty::Infer(ty::TyVar(_)) => { - push_builtin_impl(tcx.types.i32, &[]); - push_builtin_impl(tcx.types.f32, &[]); - } - - ty::Projection(_projection_ty) => { - // FIXME: add builtin impls from the associated type values found in - // trait impls of `projection_ty.trait_ref(tcx)`. - } - - // The `Copy`/`Clone` bound can only come from the environment. - ty::Param(..) | ty::Placeholder(..) | ty::UnnormalizedProjection(..) | ty::Opaque(..) => (), - - // Definitely not `Copy`/`Clone`. - ty::Dynamic(..) - | ty::Foreign(..) - | ty::Generator(..) - | ty::Str - | ty::Slice(..) - | ty::Ref(_, _, hir::Mutability::Mut) => (), - - ty::Bound(..) - | ty::GeneratorWitness(..) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty), - } -} diff --git a/src/librustc_traits/chalk_context/program_clauses/mod.rs b/src/librustc_traits/chalk_context/program_clauses/mod.rs deleted file mode 100644 index 38a4a729648..00000000000 --- a/src/librustc_traits/chalk_context/program_clauses/mod.rs +++ /dev/null @@ -1,300 +0,0 @@ -mod builtin; -mod primitive; - -use super::ChalkInferenceContext; -use rustc::traits::{ - Clause, DomainGoal, Environment, FromEnv, ProgramClause, ProgramClauseCategory, WellFormed, -}; -use rustc::ty::{self, TyCtxt}; -use rustc_hir::def_id::DefId; -use std::iter; - -use self::builtin::*; -use self::primitive::*; - -fn assemble_clauses_from_impls<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - clauses: &mut Vec>, -) { - tcx.for_each_impl(trait_def_id, |impl_def_id| { - clauses.extend(tcx.program_clauses_for(impl_def_id).into_iter().cloned()); - }); -} - -fn assemble_clauses_from_assoc_ty_values<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - clauses: &mut Vec>, -) { - tcx.for_each_impl(trait_def_id, |impl_def_id| { - for def_id in tcx.associated_item_def_ids(impl_def_id).iter() { - clauses.extend(tcx.program_clauses_for(*def_id).into_iter().cloned()); - } - }); -} - -impl ChalkInferenceContext<'cx, 'tcx> { - pub(super) fn program_clauses_impl( - &self, - environment: &Environment<'tcx>, - goal: &DomainGoal<'tcx>, - ) -> Vec> { - use rustc::infer::canonical::OriginalQueryValues; - use rustc::traits::WhereClause::*; - - let goal = self.infcx.resolve_vars_if_possible(goal); - - debug!("program_clauses(goal = {:?})", goal); - - let mut clauses = match goal { - DomainGoal::Holds(Implemented(trait_predicate)) => { - // These come from: - // * implementations of the trait itself (rule `Implemented-From-Impl`) - // * the trait decl (rule `Implemented-From-Env`) - - let mut clauses = vec![]; - - assemble_clauses_from_impls(self.infcx.tcx, trait_predicate.def_id(), &mut clauses); - - if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().sized_trait() { - assemble_builtin_sized_impls( - self.infcx.tcx, - trait_predicate.def_id(), - trait_predicate.self_ty(), - &mut clauses, - ); - } - - if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().unsize_trait() { - let source = trait_predicate.self_ty(); - let target = trait_predicate.trait_ref.substs.type_at(1); - assemble_builtin_unsize_impls( - self.infcx.tcx, - trait_predicate.def_id(), - source, - target, - &mut clauses, - ); - } - - if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().copy_trait() { - assemble_builtin_copy_clone_impls( - self.infcx.tcx, - trait_predicate.def_id(), - trait_predicate.self_ty(), - &mut clauses, - ); - } - - if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().clone_trait() { - // For all builtin impls, the conditions for `Copy` and - // `Clone` are the same. - assemble_builtin_copy_clone_impls( - self.infcx.tcx, - trait_predicate.def_id(), - trait_predicate.self_ty(), - &mut clauses, - ); - } - - // FIXME: we need to add special rules for other builtin impls: - // * `Generator` - // * `FnOnce` / `FnMut` / `Fn` - // * trait objects - // * auto traits - - // Rule `Implemented-From-Env` will be computed from the environment. - clauses - } - - DomainGoal::Holds(ProjectionEq(projection_predicate)) => { - // These come from: - // * the assoc type definition (rule `ProjectionEq-Placeholder`) - // * normalization of the assoc ty values (rule `ProjectionEq-Normalize`) - // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`) - // * implied bounds from type definitions (rule `Implied-Bound-From-Type`) - - let clauses = self - .infcx - .tcx - .program_clauses_for(projection_predicate.projection_ty.item_def_id) - .into_iter() - // only select `ProjectionEq-Placeholder` and `ProjectionEq-Normalize` - .filter(|clause| clause.category() == ProgramClauseCategory::Other) - .cloned() - .collect::>(); - - // Rules `Implied-Bound-From-Trait` and `Implied-Bound-From-Type` will be computed - // from the environment. - clauses - } - - // For outlive requirements, just assume they hold. `ResolventOps::resolvent_clause` - // will register them as actual region constraints later. - DomainGoal::Holds(RegionOutlives(..)) | DomainGoal::Holds(TypeOutlives(..)) => { - vec![Clause::Implies(ProgramClause { - goal, - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::Other, - })] - } - - DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)) => { - // These come from -- the trait decl (rule `WellFormed-TraitRef`). - self.infcx - .tcx - .program_clauses_for(trait_predicate.def_id()) - .into_iter() - // only select `WellFormed-TraitRef` - .filter(|clause| clause.category() == ProgramClauseCategory::WellFormed) - .cloned() - .collect() - } - - DomainGoal::WellFormed(WellFormed::Ty(ty)) => { - // These come from: - // * the associated type definition if `ty` refers to an unnormalized - // associated type (rule `WellFormed-AssocTy`) - // * custom rules for built-in types - // * the type definition otherwise (rule `WellFormed-Type`) - let clauses = match ty.kind { - ty::Projection(data) => self.infcx.tcx.program_clauses_for(data.item_def_id), - - // These types are always WF. - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Str - | ty::Param(..) - | ty::Placeholder(..) - | ty::Error - | ty::Never => { - let wf_clause = ProgramClause { - goal, - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::Implies(wf_clause); - - self.infcx.tcx.mk_clauses(iter::once(wf_clause)) - } - - // Always WF (recall that we do not check for parameters to be WF). - ty::RawPtr(ptr) => wf_clause_for_raw_ptr(self.infcx.tcx, ptr.mutbl), - - // Always WF (recall that we do not check for parameters to be WF). - ty::FnPtr(fn_ptr) => { - let fn_ptr = fn_ptr.skip_binder(); - wf_clause_for_fn_ptr( - self.infcx.tcx, - fn_ptr.inputs_and_output.len(), - fn_ptr.c_variadic, - fn_ptr.unsafety, - fn_ptr.abi, - ) - } - - // WF if inner type is `Sized`. - ty::Slice(..) => wf_clause_for_slice(self.infcx.tcx), - - // WF if inner type is `Sized`. - ty::Array(_, length) => wf_clause_for_array(self.infcx.tcx, length), - - // WF if all types but the last one are `Sized`. - ty::Tuple(types) => wf_clause_for_tuple(self.infcx.tcx, types.len()), - - // WF if `sub_ty` outlives `region`. - ty::Ref(_, _, mutbl) => wf_clause_for_ref(self.infcx.tcx, mutbl), - - ty::FnDef(def_id, ..) => wf_clause_for_fn_def(self.infcx.tcx, def_id), - - ty::Dynamic(..) => { - // FIXME: no rules yet for trait objects - ty::List::empty() - } - - ty::Adt(def, ..) => self.infcx.tcx.program_clauses_for(def.did), - - // FIXME: these are probably wrong - ty::Foreign(def_id) - | ty::Closure(def_id, ..) - | ty::Generator(def_id, ..) - | ty::Opaque(def_id, ..) => self.infcx.tcx.program_clauses_for(def_id), - - // Artificially trigger an ambiguity. - ty::Infer(..) => { - let tcx = self.infcx.tcx; - let types = [tcx.types.i32, tcx.types.u32, tcx.types.f32, tcx.types.f64]; - let clauses = types - .iter() - .cloned() - .map(|ty| ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(ty)), - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::WellFormed, - }) - .map(|clause| Clause::Implies(clause)); - tcx.mk_clauses(clauses) - } - - ty::GeneratorWitness(..) | ty::UnnormalizedProjection(..) | ty::Bound(..) => { - bug!("unexpected type {:?}", ty) - } - }; - - clauses - .into_iter() - .filter(|clause| clause.category() == ProgramClauseCategory::WellFormed) - .cloned() - .collect() - } - - DomainGoal::FromEnv(FromEnv::Trait(..)) => { - // These come from: - // * implied bounds from trait definitions (rule `Implied-Bound-From-Trait`) - // * implied bounds from type definitions (rule `Implied-Bound-From-Type`) - // * implied bounds from assoc type defs (rules `Implied-Trait-From-AssocTy`, - // `Implied-Bound-From-AssocTy` and `Implied-WC-From-AssocTy`) - - // All of these rules are computed in the environment. - vec![] - } - - DomainGoal::FromEnv(FromEnv::Ty(..)) => { - // There are no `FromEnv::Ty(..) :- ...` rules (this predicate only - // comes from the environment). - vec![] - } - - DomainGoal::Normalize(projection_predicate) => { - // These come from -- assoc ty values (rule `Normalize-From-Impl`). - let mut clauses = vec![]; - - assemble_clauses_from_assoc_ty_values( - self.infcx.tcx, - projection_predicate.projection_ty.trait_ref(self.infcx.tcx).def_id, - &mut clauses, - ); - - clauses - } - }; - - debug!("program_clauses: clauses = {:?}", clauses); - debug!("program_clauses: adding clauses from environment = {:?}", environment); - - let mut _orig_query_values = OriginalQueryValues::default(); - let canonical_environment = - self.infcx.canonicalize_query(environment, &mut _orig_query_values).value; - let env_clauses = self.infcx.tcx.program_clauses_for_env(canonical_environment); - - debug!("program_clauses: env_clauses = {:?}", env_clauses); - - clauses.extend(env_clauses.into_iter().cloned()); - clauses.extend(environment.clauses.iter().cloned()); - clauses - } -} diff --git a/src/librustc_traits/chalk_context/program_clauses/primitive.rs b/src/librustc_traits/chalk_context/program_clauses/primitive.rs deleted file mode 100644 index ae4afe58436..00000000000 --- a/src/librustc_traits/chalk_context/program_clauses/primitive.rs +++ /dev/null @@ -1,168 +0,0 @@ -use crate::generic_types; -use crate::lowering::Lower; -use rustc::traits::{ - Clause, Clauses, DomainGoal, GoalKind, ProgramClause, ProgramClauseCategory, WellFormed, -}; -use rustc::ty::{self, TyCtxt}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_target::spec::abi; -use std::iter; - -crate fn wf_clause_for_raw_ptr(tcx: TyCtxt<'_>, mutbl: hir::Mutability) -> Clauses<'_> { - let ptr_ty = generic_types::raw_ptr(tcx, mutbl); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(ptr_ty)), - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::Implies(wf_clause); - - // `forall { WellFormed(*const T). }` - tcx.mk_clauses(iter::once(wf_clause)) -} - -crate fn wf_clause_for_fn_ptr( - tcx: TyCtxt<'_>, - arity_and_output: usize, - variadic: bool, - unsafety: hir::Unsafety, - abi: abi::Abi, -) -> Clauses<'_> { - let fn_ptr = generic_types::fn_ptr(tcx, arity_and_output, variadic, unsafety, abi); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(fn_ptr)), - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // `forall { WellFormed(for<> fn(T1, ..., Tn) -> Tn+1). }` - // where `n + 1` == `arity_and_output` - tcx.mk_clauses(iter::once(wf_clause)) -} - -crate fn wf_clause_for_slice(tcx: TyCtxt<'_>) -> Clauses<'_> { - let ty = generic_types::bound(tcx, 0); - let slice_ty = tcx.mk_slice(ty); - - let sized_trait = match tcx.lang_items().sized_trait() { - Some(def_id) => def_id, - None => return ty::List::empty(), - }; - let sized_implemented = - ty::TraitRef { def_id: sized_trait, substs: tcx.mk_substs_trait(ty, ty::List::empty()) }; - let sized_implemented: DomainGoal<'_> = - ty::TraitPredicate { trait_ref: sized_implemented }.lower(); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(slice_ty)), - hypotheses: tcx.mk_goals(iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented)))), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // `forall { WellFormed([T]) :- Implemented(T: Sized). }` - tcx.mk_clauses(iter::once(wf_clause)) -} - -crate fn wf_clause_for_array<'tcx>( - tcx: TyCtxt<'tcx>, - length: &'tcx ty::Const<'tcx>, -) -> Clauses<'tcx> { - let ty = generic_types::bound(tcx, 0); - let array_ty = tcx.mk_ty(ty::Array(ty, length)); - - let sized_trait = match tcx.lang_items().sized_trait() { - Some(def_id) => def_id, - None => return ty::List::empty(), - }; - let sized_implemented = - ty::TraitRef { def_id: sized_trait, substs: tcx.mk_substs_trait(ty, ty::List::empty()) }; - let sized_implemented: DomainGoal<'_> = - ty::TraitPredicate { trait_ref: sized_implemented }.lower(); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(array_ty)), - hypotheses: tcx.mk_goals(iter::once(tcx.mk_goal(GoalKind::DomainGoal(sized_implemented)))), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // `forall { WellFormed([T; length]) :- Implemented(T: Sized). }` - tcx.mk_clauses(iter::once(wf_clause)) -} - -crate fn wf_clause_for_tuple(tcx: TyCtxt<'_>, arity: usize) -> Clauses<'_> { - let type_list = generic_types::type_list(tcx, arity); - let tuple_ty = tcx.mk_ty(ty::Tuple(type_list)); - - let sized_trait = match tcx.lang_items().sized_trait() { - Some(def_id) => def_id, - None => return ty::List::empty(), - }; - - // If `arity == 0` (i.e. the unit type) or `arity == 1`, this list of - // hypotheses is actually empty. - let sized_implemented = type_list[0..std::cmp::max(arity, 1) - 1] - .iter() - .map(|ty| ty::TraitRef { - def_id: sized_trait, - substs: tcx.mk_substs_trait(ty.expect_ty(), ty::List::empty()), - }) - .map(|trait_ref| ty::TraitPredicate { trait_ref }) - .map(|predicate| predicate.lower()); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(tuple_ty)), - hypotheses: tcx.mk_goals( - sized_implemented.map(|domain_goal| tcx.mk_goal(GoalKind::DomainGoal(domain_goal))), - ), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // ``` - // forall { - // WellFormed((T1, ..., Tn)) :- - // Implemented(T1: Sized), - // ... - // Implemented(Tn-1: Sized). - // } - // ``` - tcx.mk_clauses(iter::once(wf_clause)) -} - -crate fn wf_clause_for_ref(tcx: TyCtxt<'_>, mutbl: hir::Mutability) -> Clauses<'_> { - let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0))); - let ty = generic_types::bound(tcx, 1); - let ref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty, mutbl }); - - let outlives: DomainGoal<'_> = ty::OutlivesPredicate(ty, region).lower(); - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(ref_ty)), - hypotheses: tcx.mk_goals(iter::once(tcx.mk_goal(outlives.into_goal()))), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // `forall<'a, T> { WellFormed(&'a T) :- Outlives(T: 'a). }` - tcx.mk_clauses(iter::once(wf_clause)) -} - -crate fn wf_clause_for_fn_def(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> { - let fn_def = generic_types::fn_def(tcx, def_id); - - let wf_clause = ProgramClause { - goal: DomainGoal::WellFormed(WellFormed::Ty(fn_def)), - hypotheses: ty::List::empty(), - category: ProgramClauseCategory::WellFormed, - }; - let wf_clause = Clause::ForAll(ty::Binder::bind(wf_clause)); - - // `forall { WellFormed(fn some_fn(T1, ..., Tn) -> Tn+1). }` - // where `def_id` maps to the `some_fn` function definition - tcx.mk_clauses(iter::once(wf_clause)) -} diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs deleted file mode 100644 index dc6018e80ea..00000000000 --- a/src/librustc_traits/chalk_context/resolvent_ops.rs +++ /dev/null @@ -1,297 +0,0 @@ -use chalk_engine::fallible::{Fallible, NoSolution}; -use chalk_engine::{context, ExClause, Literal}; -use rustc::infer::canonical::{Canonical, CanonicalVarValues}; -use rustc::infer::{InferCtxt, LateBoundRegionConversionTime}; -use rustc::traits::{ - Clause, DomainGoal, Environment, Goal, GoalKind, InEnvironment, ProgramClause, WhereClause, -}; -use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc::ty::subst::GenericArg; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc_span::DUMMY_SP; - -use super::unify::*; -use super::{ChalkArenas, ChalkExClause, ChalkInferenceContext, ConstrainedSubst}; - -impl context::ResolventOps, ChalkArenas<'tcx>> - for ChalkInferenceContext<'cx, 'tcx> -{ - fn resolvent_clause( - &mut self, - environment: &Environment<'tcx>, - goal: &DomainGoal<'tcx>, - subst: &CanonicalVarValues<'tcx>, - clause: &Clause<'tcx>, - ) -> Fallible>> { - use chalk_engine::context::UnificationOps; - - debug!("resolvent_clause(goal = {:?}, clause = {:?})", goal, clause); - - let result = self.infcx.probe(|_| { - let ProgramClause { goal: consequence, hypotheses, .. } = match clause { - Clause::Implies(program_clause) => *program_clause, - Clause::ForAll(program_clause) => { - self.infcx - .replace_bound_vars_with_fresh_vars( - DUMMY_SP, - LateBoundRegionConversionTime::HigherRankedType, - program_clause, - ) - .0 - } - }; - - let result = - unify(self.infcx, *environment, ty::Variance::Invariant, goal, &consequence) - .map_err(|_| NoSolution)?; - - let mut ex_clause = ExClause { - subst: subst.clone(), - delayed_literals: vec![], - constraints: vec![], - subgoals: vec![], - }; - - self.into_ex_clause(result, &mut ex_clause); - - ex_clause.subgoals.extend(hypotheses.iter().map(|g| match g { - GoalKind::Not(g) => Literal::Negative(environment.with(*g)), - g => Literal::Positive(environment.with(*g)), - })); - - // If we have a goal of the form `T: 'a` or `'a: 'b`, then just - // assume it is true (no subgoals) and register it as a constraint - // instead. - match goal { - DomainGoal::Holds(WhereClause::RegionOutlives(pred)) => { - assert_eq!(ex_clause.subgoals.len(), 0); - ex_clause.constraints.push(ty::OutlivesPredicate(pred.0.into(), pred.1)); - } - - DomainGoal::Holds(WhereClause::TypeOutlives(pred)) => { - assert_eq!(ex_clause.subgoals.len(), 0); - ex_clause.constraints.push(ty::OutlivesPredicate(pred.0.into(), pred.1)); - } - - _ => (), - }; - - let canonical_ex_clause = self.canonicalize_ex_clause(&ex_clause); - Ok(canonical_ex_clause) - }); - - debug!("resolvent_clause: result = {:?}", result); - result - } - - fn apply_answer_subst( - &mut self, - ex_clause: ChalkExClause<'tcx>, - selected_goal: &InEnvironment<'tcx, Goal<'tcx>>, - answer_table_goal: &Canonical<'tcx, InEnvironment<'tcx, Goal<'tcx>>>, - canonical_answer_subst: &Canonical<'tcx, ConstrainedSubst<'tcx>>, - ) -> Fallible> { - debug!( - "apply_answer_subst(ex_clause = {:?}, selected_goal = {:?})", - self.infcx.resolve_vars_if_possible(&ex_clause), - self.infcx.resolve_vars_if_possible(selected_goal) - ); - - let (answer_subst, _) = self - .infcx - .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, canonical_answer_subst); - - let mut substitutor = AnswerSubstitutor { - infcx: self.infcx, - environment: selected_goal.environment, - answer_subst: answer_subst.subst, - binder_index: ty::INNERMOST, - ex_clause, - }; - - substitutor.relate(&answer_table_goal.value, &selected_goal).map_err(|_| NoSolution)?; - - let mut ex_clause = substitutor.ex_clause; - ex_clause.constraints.extend(answer_subst.constraints); - - debug!("apply_answer_subst: ex_clause = {:?}", ex_clause); - Ok(ex_clause) - } -} - -struct AnswerSubstitutor<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, - environment: Environment<'tcx>, - answer_subst: CanonicalVarValues<'tcx>, - binder_index: ty::DebruijnIndex, - ex_clause: ChalkExClause<'tcx>, -} - -impl AnswerSubstitutor<'cx, 'tcx> { - fn unify_free_answer_var( - &mut self, - answer_var: ty::BoundVar, - pending: GenericArg<'tcx>, - ) -> RelateResult<'tcx, ()> { - let answer_param = &self.answer_subst.var_values[answer_var]; - let pending = - &ty::fold::shift_out_vars(self.infcx.tcx, &pending, self.binder_index.as_u32()); - - super::into_ex_clause( - unify(self.infcx, self.environment, ty::Variance::Invariant, answer_param, pending)?, - &mut self.ex_clause, - ); - - Ok(()) - } -} - -impl TypeRelation<'tcx> for AnswerSubstitutor<'cx, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - // FIXME(oli-obk): learn chalk and create param envs - ty::ParamEnv::empty() - } - - fn tag(&self) -> &'static str { - "chalk_context::answer_substitutor" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn relate_with_variance>( - &mut self, - _variance: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T> { - // We don't care about variance. - self.relate(a, b) - } - - fn binders>( - &mut self, - a: &ty::Binder, - b: &ty::Binder, - ) -> RelateResult<'tcx, ty::Binder> { - self.binder_index.shift_in(1); - let result = self.relate(a.skip_binder(), b.skip_binder())?; - self.binder_index.shift_out(1); - Ok(ty::Binder::bind(result)) - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let b = self.infcx.shallow_resolve(b); - debug!("AnswerSubstitutor::tys(a = {:?}, b = {:?})", a, b); - - if let &ty::Bound(debruijn, bound_ty) = &a.kind { - // Free bound var - if debruijn == self.binder_index { - self.unify_free_answer_var(bound_ty.var, b.into())?; - return Ok(b); - } - } - - match (&a.kind, &b.kind) { - (&ty::Bound(a_debruijn, a_bound), &ty::Bound(b_debruijn, b_bound)) => { - assert_eq!(a_debruijn, b_debruijn); - assert_eq!(a_bound.var, b_bound.var); - Ok(a) - } - - // Those should have been canonicalized away. - (ty::Placeholder(..), _) => { - bug!("unexpected placeholder ty in `AnswerSubstitutor`: {:?} ", a); - } - - // Everything else should just be a perfect match as well, - // and we forbid inference variables. - _ => match ty::relate::super_relate_tys(self, a, b) { - Ok(ty) => Ok(ty), - Err(err) => bug!("type mismatch in `AnswerSubstitutor`: {}", err), - }, - } - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - let b = match b { - &ty::ReVar(vid) => self - .infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .opportunistic_resolve_var(self.infcx.tcx, vid), - - other => other, - }; - - if let &ty::ReLateBound(debruijn, bound) = a { - // Free bound region - if debruijn == self.binder_index { - self.unify_free_answer_var(bound.assert_bound_var(), b.into())?; - return Ok(b); - } - } - - match (a, b) { - (&ty::ReLateBound(a_debruijn, a_bound), &ty::ReLateBound(b_debruijn, b_bound)) => { - assert_eq!(a_debruijn, b_debruijn); - assert_eq!(a_bound.assert_bound_var(), b_bound.assert_bound_var()); - } - - (ty::ReStatic, ty::ReStatic) | (ty::ReErased, ty::ReErased) => (), - - (ty::ReEmpty(a_ui), ty::ReEmpty(b_ui)) => { - assert_eq!(a_ui, b_ui); - } - - (&ty::ReFree(a_free), &ty::ReFree(b_free)) => { - assert_eq!(a_free, b_free); - } - - _ => bug!("unexpected regions in `AnswerSubstitutor`: {:?}, {:?}", a, b), - } - - Ok(a) - } - - fn consts( - &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), .. } = a { - if *debruijn == self.binder_index { - self.unify_free_answer_var(*bound_ct, b.into())?; - return Ok(b); - } - } - - match (a, b) { - ( - ty::Const { val: ty::ConstKind::Bound(a_debruijn, a_bound), .. }, - ty::Const { val: ty::ConstKind::Bound(b_debruijn, b_bound), .. }, - ) => { - assert_eq!(a_debruijn, b_debruijn); - assert_eq!(a_bound, b_bound); - Ok(a) - } - - // Everything else should just be a perfect match as well, - // and we forbid inference variables. - _ => match ty::relate::super_relate_consts(self, a, b) { - Ok(ct) => Ok(ct), - Err(err) => bug!("const mismatch in `AnswerSubstitutor`: {}", err), - }, - } - } -} diff --git a/src/librustc_traits/chalk_context/unify.rs b/src/librustc_traits/chalk_context/unify.rs deleted file mode 100644 index fcb3c3b1773..00000000000 --- a/src/librustc_traits/chalk_context/unify.rs +++ /dev/null @@ -1,85 +0,0 @@ -use rustc::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate}; -use rustc::infer::{InferCtxt, RegionVariableOrigin}; -use rustc::traits::{DomainGoal, Environment, Goal, InEnvironment}; -use rustc::ty; -use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_span::DUMMY_SP; - -crate struct UnificationResult<'tcx> { - crate goals: Vec>>, - crate constraints: Vec>, -} - -crate fn unify<'me, 'tcx, T: Relate<'tcx>>( - infcx: &'me InferCtxt<'me, 'tcx>, - environment: Environment<'tcx>, - variance: ty::Variance, - a: &T, - b: &T, -) -> RelateResult<'tcx, UnificationResult<'tcx>> { - debug!( - "unify( - a = {:?}, - b = {:?}, - environment = {:?}, - )", - a, b, environment - ); - - let mut delegate = ChalkTypeRelatingDelegate::new(infcx, environment); - - TypeRelating::new(infcx, &mut delegate, variance).relate(a, b)?; - - debug!("unify: goals = {:?}, constraints = {:?}", delegate.goals, delegate.constraints); - - Ok(UnificationResult { goals: delegate.goals, constraints: delegate.constraints }) -} - -struct ChalkTypeRelatingDelegate<'me, 'tcx> { - infcx: &'me InferCtxt<'me, 'tcx>, - environment: Environment<'tcx>, - goals: Vec>>, - constraints: Vec>, -} - -impl ChalkTypeRelatingDelegate<'me, 'tcx> { - fn new(infcx: &'me InferCtxt<'me, 'tcx>, environment: Environment<'tcx>) -> Self { - Self { infcx, environment, goals: Vec::new(), constraints: Vec::new() } - } -} - -impl TypeRelatingDelegate<'tcx> for &mut ChalkTypeRelatingDelegate<'_, 'tcx> { - fn create_next_universe(&mut self) -> ty::UniverseIndex { - self.infcx.create_next_universe() - } - - fn next_existential_region_var(&mut self, _was_placeholder: bool) -> ty::Region<'tcx> { - self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)) - } - - fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> { - self.infcx.tcx.mk_region(ty::RePlaceholder(placeholder)) - } - - fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { - self.infcx - .next_region_var_in_universe(RegionVariableOrigin::MiscVariable(DUMMY_SP), universe) - } - - fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { - self.constraints.push(ty::OutlivesPredicate(sup.into(), sub)); - } - - fn push_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>) { - let goal = self.environment.with(self.infcx.tcx.mk_goal(domain_goal.into_goal())); - self.goals.push(goal); - } - - fn normalization() -> NormalizationStrategy { - NormalizationStrategy::Lazy - } - - fn forbid_inference_vars() -> bool { - false - } -} diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 346d2a931d1..b13a7a3acb1 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -1,14 +1,21 @@ -use rustc::infer::canonical::{Canonical, QueryResponse}; -use rustc::traits::query::dropck_outlives::trivial_dropck_outlives; -use rustc::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint}; -use rustc::traits::query::{CanonicalTyGoal, NoSolution}; -use rustc::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt}; use rustc::ty::query::Providers; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; +use rustc_infer::infer::canonical::{Canonical, QueryResponse}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::{Span, DUMMY_SP}; +use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives; +use rustc_trait_selection::traits::query::dropck_outlives::{ + DropckOutlivesResult, DtorckConstraint, +}; +use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; +use rustc_trait_selection::traits::{ + Normalized, ObligationCause, TraitEngine, TraitEngineExt as _, +}; crate fn provide(p: &mut Providers<'_>) { *p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p }; @@ -91,7 +98,7 @@ fn dropck_outlives<'tcx>( // information and will just decrease the speed at which we can emit these errors // (since we'll be printing for just that much longer for the often enormous types // that result here). - if result.overflows.len() >= 1 { + if !result.overflows.is_empty() { break; } diff --git a/src/librustc_traits/evaluate_obligation.rs b/src/librustc_traits/evaluate_obligation.rs index 3ad1b223a84..87895d8e384 100644 --- a/src/librustc_traits/evaluate_obligation.rs +++ b/src/librustc_traits/evaluate_obligation.rs @@ -1,10 +1,11 @@ -use rustc::traits::query::CanonicalPredicateGoal; -use rustc::traits::{ - EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode, -}; use rustc::ty::query::Providers; use rustc::ty::{ParamEnvAnd, TyCtxt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_span::source_map::DUMMY_SP; +use rustc_trait_selection::traits::query::CanonicalPredicateGoal; +use rustc_trait_selection::traits::{ + EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode, +}; crate fn provide(p: &mut Providers<'_>) { *p = Providers { evaluate_obligation, ..*p }; diff --git a/src/librustc_traits/generic_types.rs b/src/librustc_traits/generic_types.rs deleted file mode 100644 index e1a9ec56f8b..00000000000 --- a/src/librustc_traits/generic_types.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! Utilities for creating generic types with bound vars in place of parameter values. - -use rustc::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_target::spec::abi; - -crate fn bound(tcx: TyCtxt<'tcx>, index: u32) -> Ty<'tcx> { - let ty = ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(index).into()); - tcx.mk_ty(ty) -} - -crate fn raw_ptr(tcx: TyCtxt<'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> { - tcx.mk_ptr(ty::TypeAndMut { ty: bound(tcx, 0), mutbl }) -} - -crate fn fn_ptr( - tcx: TyCtxt<'tcx>, - arity_and_output: usize, - c_variadic: bool, - unsafety: hir::Unsafety, - abi: abi::Abi, -) -> Ty<'tcx> { - let inputs_and_output = tcx.mk_type_list( - (0..arity_and_output) - .into_iter() - .map(|i| ty::BoundVar::from(i)) - // DebruijnIndex(1) because we are going to inject these in a `PolyFnSig` - .map(|var| tcx.mk_ty(ty::Bound(ty::DebruijnIndex::from(1usize), var.into()))), - ); - - let fn_sig = ty::Binder::bind(ty::FnSig { inputs_and_output, c_variadic, unsafety, abi }); - tcx.mk_fn_ptr(fn_sig) -} - -crate fn type_list(tcx: TyCtxt<'tcx>, arity: usize) -> SubstsRef<'tcx> { - tcx.mk_substs( - (0..arity) - .into_iter() - .map(|i| ty::BoundVar::from(i)) - .map(|var| tcx.mk_ty(ty::Bound(ty::INNERMOST, var.into()))) - .map(|ty| GenericArg::from(ty)), - ) -} - -crate fn ref_ty(tcx: TyCtxt<'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> { - let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(0))); - - tcx.mk_ref(region, ty::TypeAndMut { ty: bound(tcx, 1), mutbl }) -} - -crate fn fn_def(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { - tcx.mk_ty(ty::FnDef(def_id, InternalSubsts::bound_vars_for_item(tcx, def_id))) -} - -crate fn closure(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { - tcx.mk_closure(def_id, InternalSubsts::bound_vars_for_item(tcx, def_id)) -} - -crate fn generator(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { - tcx.mk_generator( - def_id, - InternalSubsts::bound_vars_for_item(tcx, def_id), - hir::Movability::Movable, - ) -} diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 40f821c29d3..4505a1e59d9 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -1,18 +1,20 @@ //! Provider for the `implied_outlives_bounds` query. //! Do not call this query directory. See [`rustc::traits::query::implied_outlives_bounds`]. -use rustc::infer::canonical::{self, Canonical}; -use rustc::infer::InferCtxt; -use rustc::traits::query::outlives_bounds::OutlivesBound; -use rustc::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; -use rustc::traits::wf; -use rustc::traits::FulfillmentContext; -use rustc::traits::{TraitEngine, TraitEngineExt}; use rustc::ty::outlives::Component; use rustc::ty::query::Providers; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as hir; +use rustc_infer::infer::canonical::{self, Canonical}; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::DUMMY_SP; +use rustc_trait_selection::infer::InferCtxtBuilderExt; +use rustc_trait_selection::traits::query::outlives_bounds::OutlivesBound; +use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; +use rustc_trait_selection::traits::wf; +use rustc_trait_selection::traits::FulfillmentContext; +use rustc_trait_selection::traits::TraitEngine; use smallvec::{smallvec, SmallVec}; crate fn provide(p: &mut Providers<'_>) { @@ -84,7 +86,7 @@ fn compute_implied_outlives_bounds<'tcx>( // to avoids duplicate errors that otherwise show up. fulfill_cx.register_predicate_obligations( infcx, - obligations.iter().filter(|o| o.predicate.has_infer_types()).cloned(), + obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(), ); // From the full set of obligations, just filter down to the diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index fefe82fdece..894e3ef3a8f 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -11,10 +11,8 @@ extern crate log; #[macro_use] extern crate rustc; -mod chalk_context; mod dropck_outlives; mod evaluate_obligation; -mod generic_types; mod implied_outlives_bounds; pub mod lowering; mod normalize_erasing_regions; @@ -28,7 +26,6 @@ pub fn provide(p: &mut Providers<'_>) { evaluate_obligation::provide(p); implied_outlives_bounds::provide(p); lowering::provide(p); - chalk_context::provide(p); normalize_projection_ty::provide(p); normalize_erasing_regions::provide(p); type_op::provide(p); diff --git a/src/librustc_traits/lowering/environment.rs b/src/librustc_traits/lowering/environment.rs index 0e26e9461f4..69d0bd09296 100644 --- a/src/librustc_traits/lowering/environment.rs +++ b/src/librustc_traits/lowering/environment.rs @@ -185,12 +185,12 @@ crate fn environment(tcx: TyCtxt<'_>, def_id: DefId) -> Environment<'_> { let node_kind = match node { Node::TraitItem(item) => match item.kind { - TraitItemKind::Method(..) => NodeKind::Fn, + TraitItemKind::Fn(..) => NodeKind::Fn, _ => NodeKind::Other, }, Node::ImplItem(item) => match item.kind { - ImplItemKind::Method(..) => NodeKind::Fn, + ImplItemKind::Fn(..) => NodeKind::Fn, _ => NodeKind::Other, }, diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index b77c603da9a..3a0c36a84ae 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -9,12 +9,12 @@ use rustc::traits::{ use rustc::ty::query::Providers; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::{self, List, TyCtxt}; +use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_span::symbol::sym; -use syntax::ast; use std::iter; @@ -108,13 +108,13 @@ impl<'tcx> Lower> for ty::Predicate<'tcx> { } } -/// Used for implied bounds related rules (see rustc guide). +/// Used for implied bounds related rules (see rustc dev guide). trait IntoFromEnvGoal { /// Transforms an existing goal into a `FromEnv` goal. fn into_from_env_goal(self) -> Self; } -/// Used for well-formedness related rules (see rustc guide). +/// Used for well-formedness related rules (see rustc dev guide). trait IntoWellFormedGoal { /// Transforms an existing goal into a `WellFormed` goal. fn into_well_formed_goal(self) -> Self; @@ -178,7 +178,7 @@ crate fn program_clauses_for(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> { fn program_clauses_for_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> { // `trait Trait where WC { .. } // P0 == Self` - // Rule Implemented-From-Env (see rustc guide) + // Rule Implemented-From-Env (see rustc dev guide) // // ``` // forall { @@ -256,7 +256,7 @@ fn program_clauses_for_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Clauses<'_> { // `WellFormed(WC)` let wf_conditions = where_clauses - .into_iter() + .iter() .map(|wc| wc.subst(tcx, bound_vars)) .map(|wc| wc.map_bound(|goal| goal.into_well_formed_goal())); @@ -282,7 +282,7 @@ fn program_clauses_for_impl(tcx: TyCtxt<'tcx>, def_id: DefId) -> Clauses<'tcx> { return List::empty(); } - // Rule Implemented-From-Impl (see rustc guide) + // Rule Implemented-From-Impl (see rustc dev guide) // // `impl Trait for A0 where WC { .. }` // @@ -501,7 +501,7 @@ pub fn program_clauses_for_associated_type_def(tcx: TyCtxt<'_>, item_id: DefId) } pub fn program_clauses_for_associated_type_value(tcx: TyCtxt<'_>, item_id: DefId) -> Clauses<'_> { - // Rule Normalize-From-Impl (see rustc guide) + // Rule Normalize-From-Impl (see rustc dev guide) // // ``` // impl Trait for A0 { @@ -603,8 +603,8 @@ impl ClauseDumper<'tcx> { impl Visitor<'tcx> for ClauseDumper<'tcx> { type Map = Map<'tcx>; - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir()) + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.tcx.hir()) } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index e81b0242d61..c2fb237a05b 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -1,7 +1,9 @@ use rustc::traits::query::NoSolution; -use rustc::traits::{Normalized, ObligationCause}; use rustc::ty::query::Providers; use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_trait_selection::traits::{Normalized, ObligationCause}; use std::sync::atomic::Ordering; crate fn provide(p: &mut Providers<'_>) { diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs index e50ca485e0a..57abff769de 100644 --- a/src/librustc_traits/normalize_projection_ty.rs +++ b/src/librustc_traits/normalize_projection_ty.rs @@ -1,10 +1,15 @@ -use rustc::infer::canonical::{Canonical, QueryResponse}; -use rustc::traits::query::{normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution}; -use rustc::traits::{self, ObligationCause, SelectionContext, TraitEngineExt}; use rustc::ty::query::Providers; use rustc::ty::{ParamEnvAnd, TyCtxt}; use rustc_hir as hir; +use rustc_infer::infer::canonical::{Canonical, QueryResponse}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::DUMMY_SP; +use rustc_trait_selection::infer::InferCtxtBuilderExt; +use rustc_trait_selection::traits::query::{ + normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution, +}; +use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext}; use std::sync::atomic::Ordering; crate fn provide(p: &mut Providers<'_>) { diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index 149c42e9c5e..e174c040e0d 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -1,13 +1,3 @@ -use rustc::infer::at::ToTrace; -use rustc::infer::canonical::{Canonical, QueryResponse}; -use rustc::infer::InferCtxt; -use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType; -use rustc::traits::query::type_op::eq::Eq; -use rustc::traits::query::type_op::normalize::Normalize; -use rustc::traits::query::type_op::prove_predicate::ProvePredicate; -use rustc::traits::query::type_op::subtype::Subtype; -use rustc::traits::query::{Fallible, NoSolution}; -use rustc::traits::{Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt}; use rustc::ty::query::Providers; use rustc::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts}; use rustc::ty::{ @@ -15,7 +5,21 @@ use rustc::ty::{ }; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::at::ToTrace; +use rustc_infer::infer::canonical::{Canonical, QueryResponse}; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::DUMMY_SP; +use rustc_trait_selection::infer::InferCtxtBuilderExt; +use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::query::normalize::AtExt; +use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType; +use rustc_trait_selection::traits::query::type_op::eq::Eq; +use rustc_trait_selection::traits::query::type_op::normalize::Normalize; +use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate; +use rustc_trait_selection::traits::query::type_op::subtype::Subtype; +use rustc_trait_selection::traits::query::{Fallible, NoSolution}; +use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine}; use std::fmt; crate fn provide(p: &mut Providers<'_>) { diff --git a/src/librustc_ty/Cargo.toml b/src/librustc_ty/Cargo.toml index fb0d93fe5eb..cf0b4b82eea 100644 --- a/src/librustc_ty/Cargo.toml +++ b/src/librustc_ty/Cargo.toml @@ -13,4 +13,8 @@ log = "0.4" rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_hir = { path = "../librustc_hir" } +rustc_infer = { path = "../librustc_infer" } rustc_span = { path = "../librustc_span" } +rustc_session = { path = "../librustc_session" } +rustc_target = { path = "../librustc_target" } +rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_ty/common_traits.rs b/src/librustc_ty/common_traits.rs index 9fe8a19311f..311ba383f30 100644 --- a/src/librustc_ty/common_traits.rs +++ b/src/librustc_ty/common_traits.rs @@ -1,9 +1,10 @@ //! Queries for checking whether a type implements one of a few common traits. use rustc::middle::lang_items; -use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits; fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, lang_items::CopyTraitLangItem) diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs new file mode 100644 index 00000000000..a5abe7b6413 --- /dev/null +++ b/src/librustc_ty/instance.rs @@ -0,0 +1,166 @@ +use rustc::ty::subst::SubstsRef; +use rustc::ty::{self, Instance, TyCtxt, TypeFoldable}; +use rustc_hir::def_id::DefId; +use rustc_span::sym; +use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits; + +use log::debug; + +pub fn resolve_instance<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + def_id: DefId, + substs: SubstsRef<'tcx>, +) -> Option> { + debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); + let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { + debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env); + let item = tcx.associated_item(def_id); + resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) + } else { + let ty = tcx.type_of(def_id); + let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty); + + let def = match item_type.kind { + ty::FnDef(..) + if { + let f = item_type.fn_sig(tcx); + f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic + } => + { + debug!(" => intrinsic"); + ty::InstanceDef::Intrinsic(def_id) + } + ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => { + let ty = substs.type_at(0); + + if ty.needs_drop(tcx, param_env) { + // `DropGlue` requires a monomorphic aka concrete type. + if ty.needs_subst() { + return None; + } + + debug!(" => nontrivial drop glue"); + ty::InstanceDef::DropGlue(def_id, Some(ty)) + } else { + debug!(" => trivial drop glue"); + ty::InstanceDef::DropGlue(def_id, None) + } + } + _ => { + debug!(" => free item"); + ty::InstanceDef::Item(def_id) + } + }; + Some(Instance { def, substs }) + }; + debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result); + result +} + +fn resolve_associated_item<'tcx>( + tcx: TyCtxt<'tcx>, + trait_item: &ty::AssocItem, + param_env: ty::ParamEnv<'tcx>, + trait_id: DefId, + rcvr_substs: SubstsRef<'tcx>, +) -> Option> { + let def_id = trait_item.def_id; + debug!( + "resolve_associated_item(trait_item={:?}, \ + param_env={:?}, \ + trait_id={:?}, \ + rcvr_substs={:?})", + def_id, param_env, trait_id, rcvr_substs + ); + + let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); + let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref)))?; + + // Now that we know which impl is being used, we can dispatch to + // the actual function: + match vtbl { + traits::VtableImpl(impl_data) => { + let (def_id, substs) = + traits::find_associated_item(tcx, param_env, trait_item, rcvr_substs, &impl_data); + + let resolved_item = tcx.associated_item(def_id); + + // Since this is a trait item, we need to see if the item is either a trait default item + // or a specialization because we can't resolve those unless we can `Reveal::All`. + // NOTE: This should be kept in sync with the similar code in + // `rustc::traits::project::assemble_candidates_from_impls()`. + let eligible = if !resolved_item.defaultness.is_default() { + true + } else if param_env.reveal == traits::Reveal::All { + !trait_ref.needs_subst() + } else { + false + }; + + if !eligible { + return None; + } + + let substs = tcx.erase_regions(&substs); + Some(ty::Instance::new(def_id, substs)) + } + traits::VtableGenerator(generator_data) => Some(Instance { + def: ty::InstanceDef::Item(generator_data.generator_def_id), + substs: generator_data.substs, + }), + traits::VtableClosure(closure_data) => { + let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); + Some(Instance::resolve_closure( + tcx, + closure_data.closure_def_id, + closure_data.substs, + trait_closure_kind, + )) + } + traits::VtableFnPointer(ref data) => { + // `FnPtrShim` requires a monomorphic aka concrete type. + if data.fn_ty.needs_subst() { + return None; + } + + Some(Instance { + def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), + substs: rcvr_substs, + }) + } + traits::VtableObject(ref data) => { + let index = traits::get_vtable_index_of_object_method(tcx, data, def_id); + Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }) + } + traits::VtableBuiltin(..) => { + if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() { + // FIXME(eddyb) use lang items for methods instead of names. + let name = tcx.item_name(def_id); + if name == sym::clone { + let self_ty = trait_ref.self_ty(); + + // `CloneShim` requires a monomorphic aka concrete type. + if self_ty.needs_subst() { + return None; + } + + Some(Instance { + def: ty::InstanceDef::CloneShim(def_id, self_ty), + substs: rcvr_substs, + }) + } else { + assert_eq!(name, sym::clone_from); + + // Use the default `fn clone_from` from `trait Clone`. + let substs = tcx.erase_regions(&rcvr_substs); + Some(ty::Instance::new(def_id, substs)) + } + } else { + None + } + } + traits::VtableAutoImpl(..) | traits::VtableParam(..) | traits::VtableTraitAlias(..) => None, + } +} diff --git a/src/librustc_ty/lib.rs b/src/librustc_ty/lib.rs index 7eef19b94e4..f9ee4e20d27 100644 --- a/src/librustc_ty/lib.rs +++ b/src/librustc_ty/lib.rs @@ -17,6 +17,7 @@ extern crate log; use rustc::ty::query::Providers; mod common_traits; +pub mod instance; mod needs_drop; mod ty; diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index ddb7c8bc791..4b522997537 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -1,13 +1,13 @@ use rustc::hir::map as hir_map; -use rustc::session::CrateDisambiguator; -use rustc::traits::{self}; use rustc::ty::subst::Subst; use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_session::CrateDisambiguator; use rustc_span::symbol::Symbol; use rustc_span::Span; +use rustc_trait_selection::traits; fn sized_constraint_for_ty<'tcx>( tcx: TyCtxt<'tcx>, @@ -210,10 +210,9 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { } } -fn associated_items<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [ty::AssocItem] { - tcx.arena.alloc_from_iter( - tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)), - ) +fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AssociatedItems { + let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)); + tcx.arena.alloc(ty::AssociatedItems::new(items)) } fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span { @@ -253,11 +252,8 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // are any errors at that point, so after type checking you can be // sure that this will succeed without errors anyway. - let unnormalized_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - traits::Reveal::UserFacing, - tcx.sess.opts.debugging_opts.chalk.then_some(def_id), - ); + let unnormalized_env = + ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing, None); let body_id = tcx.hir().as_local_hir_id(def_id).map_or(hir::DUMMY_HIR_ID, |id| { tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id) @@ -277,8 +273,7 @@ fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol { } fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { - assert_eq!(crate_num, LOCAL_CRATE); - tcx.hir().crate_hash + tcx.index_hir(crate_num).crate_hash } fn instance_def_size_estimate<'tcx>( diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 748bfcc7946..e61a36f844f 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -19,7 +19,10 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } rustc_target = { path = "../librustc_target" } +rustc_session = { path = "../librustc_session" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } -syntax = { path = "../libsyntax" } +rustc_ast = { path = "../librustc_ast" } rustc_span = { path = "../librustc_span" } rustc_index = { path = "../librustc_index" } +rustc_infer = { path = "../librustc_infer" } +rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_typeck/README.md b/src/librustc_typeck/README.md index fdcbd935524..b61dbd8c964 100644 --- a/src/librustc_typeck/README.md +++ b/src/librustc_typeck/README.md @@ -1,5 +1,5 @@ For high-level intro to how type checking works in rustc, see the -[type checking] chapter of the [rustc guide]. +[type checking] chapter of the [rustc dev guide]. -[type checking]: https://rust-lang.github.io/rustc-guide/type-checking.html -[rustc guide]: https://rust-lang.github.io/rustc-guide/ +[type checking]: https://rustc-dev-guide.rust-lang.org/type-checking.html +[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/ diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 0e7c10541ca..9a8d161572b 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -6,36 +6,35 @@ // ignore-tidy-filelength use crate::collect::PlaceholderHirTyCollector; -use crate::lint; use crate::middle::lang_items::SizedTraitLangItem; use crate::middle::resolve_lifetime as rl; -use crate::namespace::Namespace; use crate::require_c_abi_if_c_variadic; use crate::util::common::ErrorReported; -use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; -use rustc::session::parse::feature_err; -use rustc::traits; -use rustc::traits::astconv_object_safety_violations; -use rustc::traits::error_reporting::report_object_safety_error; -use rustc::traits::wf::object_region_bounds; use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc::ty::{GenericParamDef, GenericParamDefKind}; +use rustc_ast::ast; +use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId}; use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind, Res}; +use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::print; use rustc_hir::{Constness, ExprKind, GenericArg, GenericArgs}; +use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, LATE_BOUND_LIFETIME_ARGUMENTS}; +use rustc_session::parse::feature_err; +use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::{MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi; -use smallvec::SmallVec; -use syntax::ast; -use syntax::util::lev_distance::find_best_match_for_name; +use rustc_trait_selection::traits; +use rustc_trait_selection::traits::astconv_object_safety_violations; +use rustc_trait_selection::traits::error_reporting::report_object_safety_error; +use rustc_trait_selection::traits::wf::object_region_bounds; +use smallvec::SmallVec; use std::collections::BTreeSet; use std::iter; use std::slice; @@ -133,6 +132,15 @@ enum GenericArgPosition { MethodCall, } +/// A marker denoting that the generic arguments that were +/// provided did not match the respective generic parameters. +pub struct GenericArgCountMismatch { + /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`). + pub reported: Option, + /// A list of spans of arguments provided that were not valid. + pub invalid_args: Vec, +} + impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn ast_region_to_region( &self, @@ -263,7 +271,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def: &ty::Generics, seg: &hir::PathSegment<'_>, is_method_call: bool, - ) -> bool { + ) -> Result<(), GenericArgCountMismatch> { let empty_args = hir::GenericArgs::none(); let suppress_mismatch = Self::check_impl_trait(tcx, seg, &def); Self::check_generic_arg_count( @@ -275,7 +283,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def.parent.is_none() && def.has_self, // `has_self` seg.infer_args || suppress_mismatch, // `infer_args` ) - .0 } /// Checks that the correct number of generic arguments have been provided. @@ -288,7 +295,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { position: GenericArgPosition, has_self: bool, infer_args: bool, - ) -> (bool, Option>) { + ) -> Result<(), GenericArgCountMismatch> { // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. // that lifetimes will proceed types. So it suffices to check the number of each generic // arguments in order to validate them with respect to the generic parameters. @@ -314,7 +321,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Prohibit explicit lifetime arguments if late-bound lifetime parameters are present. - let mut reported_late_bound_region_err = None; + let mut explicit_lifetimes = Ok(()); if !infer_lifetimes { if let Some(span_late) = def.has_late_bound_regions { let msg = "cannot specify lifetime arguments explicitly \ @@ -324,125 +331,150 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if position == GenericArgPosition::Value && arg_counts.lifetimes != param_counts.lifetimes { + explicit_lifetimes = Err(true); let mut err = tcx.sess.struct_span_err(span, msg); err.span_note(span_late, note); err.emit(); - reported_late_bound_region_err = Some(true); } else { + explicit_lifetimes = Err(false); let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note.to_string()); tcx.struct_span_lint_hir( - lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, + LATE_BOUND_LIFETIME_ARGUMENTS, args.args[0].id(), multispan, |lint| lint.build(msg).emit(), ); - reported_late_bound_region_err = Some(false); } } } - let check_kind_count = |kind, required, permitted, provided, offset| { - debug!( - "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", - kind, required, permitted, provided, offset - ); - // We enforce the following: `required` <= `provided` <= `permitted`. - // For kinds without defaults (e.g.., lifetimes), `required == permitted`. - // For other kinds (i.e., types), `permitted` may be greater than `required`. - if required <= provided && provided <= permitted { - return (reported_late_bound_region_err.unwrap_or(false), None); - } - - // Unfortunately lifetime and type parameter mismatches are typically styled - // differently in diagnostics, which means we have a few cases to consider here. - let (bound, quantifier) = if required != permitted { - if provided < required { - (required, "at least ") - } else { - // provided > permitted - (permitted, "at most ") + let check_kind_count = + |kind, required, permitted, provided, offset, unexpected_spans: &mut Vec| { + debug!( + "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", + kind, required, permitted, provided, offset + ); + // We enforce the following: `required` <= `provided` <= `permitted`. + // For kinds without defaults (e.g.., lifetimes), `required == permitted`. + // For other kinds (i.e., types), `permitted` may be greater than `required`. + if required <= provided && provided <= permitted { + return Ok(()); } - } else { - (required, "") - }; - let mut potential_assoc_types: Option> = None; - let (spans, label) = if required == permitted && provided > permitted { - // In the case when the user has provided too many arguments, - // we want to point to the unexpected arguments. - let spans: Vec = args.args[offset + permitted..offset + provided] - .iter() - .map(|arg| arg.span()) - .collect(); - potential_assoc_types = Some(spans.clone()); - (spans, format!("unexpected {} argument", kind)) - } else { - ( - vec![span], - format!( - "expected {}{} {} argument{}", - quantifier, - bound, - kind, - pluralize!(bound), + // Unfortunately lifetime and type parameter mismatches are typically styled + // differently in diagnostics, which means we have a few cases to consider here. + let (bound, quantifier) = if required != permitted { + if provided < required { + (required, "at least ") + } else { + // provided > permitted + (permitted, "at most ") + } + } else { + (required, "") + }; + + let (spans, label) = if required == permitted && provided > permitted { + // In the case when the user has provided too many arguments, + // we want to point to the unexpected arguments. + let spans: Vec = args.args[offset + permitted..offset + provided] + .iter() + .map(|arg| arg.span()) + .collect(); + unexpected_spans.extend(spans.clone()); + (spans, format!("unexpected {} argument", kind)) + } else { + ( + vec![span], + format!( + "expected {}{} {} argument{}", + quantifier, + bound, + kind, + pluralize!(bound), + ), + ) + }; + + let mut err = tcx.sess.struct_span_err_with_code( + spans.clone(), + &format!( + "wrong number of {} arguments: expected {}{}, found {}", + kind, quantifier, bound, provided, ), - ) - }; + DiagnosticId::Error("E0107".into()), + ); + for span in spans { + err.span_label(span, label.as_str()); + } + err.emit(); - let mut err = tcx.sess.struct_span_err_with_code( - spans.clone(), - &format!( - "wrong number of {} arguments: expected {}{}, found {}", - kind, quantifier, bound, provided, - ), - DiagnosticId::Error("E0107".into()), - ); - for span in spans { - err.span_label(span, label.as_str()); - } - err.emit(); + Err(true) + }; - ( - provided > required, // `suppress_error` - potential_assoc_types, - ) - }; + let mut arg_count_correct = explicit_lifetimes; + let mut unexpected_spans = vec![]; - if reported_late_bound_region_err.is_none() + if arg_count_correct.is_ok() && (!infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes) { - check_kind_count( + arg_count_correct = check_kind_count( "lifetime", param_counts.lifetimes, param_counts.lifetimes, arg_counts.lifetimes, 0, - ); + &mut unexpected_spans, + ) + .and(arg_count_correct); } // FIXME(const_generics:defaults) if !infer_args || arg_counts.consts > param_counts.consts { - check_kind_count( + arg_count_correct = check_kind_count( "const", param_counts.consts, param_counts.consts, arg_counts.consts, arg_counts.lifetimes + arg_counts.types, - ); + &mut unexpected_spans, + ) + .and(arg_count_correct); } // Note that type errors are currently be emitted *after* const errors. if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize { - check_kind_count( + arg_count_correct = check_kind_count( "type", param_counts.types - defaults.types - has_self as usize, param_counts.types - has_self as usize, arg_counts.types, arg_counts.lifetimes, + &mut unexpected_spans, ) - } else { - (reported_late_bound_region_err.unwrap_or(false), None) + .and(arg_count_correct); } + + arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { + reported: if reported_err { Some(ErrorReported) } else { None }, + invalid_args: unexpected_spans, + }) + } + + /// Report an error that a generic argument did not match the generic parameter that was + /// expected. + fn generic_arg_mismatch_err(sess: &Session, arg: &GenericArg<'_>, kind: &'static str) { + let mut err = struct_span_err!( + sess, + arg.span(), + E0747, + "{} provided when a {} was expected", + arg.descr(), + kind, + ); + // This note will be true as long as generic parameters are strictly ordered by their kind. + err.note(&format!("{} arguments must be provided before {} arguments", kind, arg.descr())); + err.emit(); } /// Creates the relevant generic argument substitutions @@ -480,8 +512,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs: &[subst::GenericArg<'tcx>], has_self: bool, self_ty: Option>, + arg_count_correct: bool, args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool), - provided_kind: impl Fn(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>, + mut provided_kind: impl FnMut(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>, mut inferred_kind: impl FnMut( Option<&[subst::GenericArg<'tcx>]>, &GenericParamDef, @@ -503,7 +536,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // methods in `subst.rs`, so that we can iterate over the arguments and // parameters in lock-step linearly, instead of trying to match each pair. let mut substs: SmallVec<[subst::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count); - // Iterate over each segment of the path. while let Some((def_id, defs)) = stack.pop() { let mut params = defs.params.iter().peekable(); @@ -540,6 +572,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut args = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()).peekable(); + // If we encounter a type or const when we expect a lifetime, we infer the lifetimes. + // If we later encounter a lifetime, we know that the arguments were provided in the + // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be + // inferred, so we can use it for diagnostics later. + let mut force_infer_lt = None; + loop { // We're going to iterate through the generic arguments that the user // provided, matching them with the generic parameters we expect. @@ -560,30 +598,58 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // We expected a lifetime argument, but got a type or const // argument. That means we're inferring the lifetimes. substs.push(inferred_kind(None, param, infer_args)); + force_infer_lt = Some(arg); params.next(); } - (_, _) => { + (_, kind) => { // We expected one kind of parameter, but the user provided - // another. This is an error, but we need to handle it - // gracefully so we can report sensible errors. - // In this case, we're simply going to infer this argument. - args.next(); + // another. This is an error. However, if we already know that + // the arguments don't match up with the parameters, we won't issue + // an additional error, as the user already knows what's wrong. + if arg_count_correct { + Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr()); + } + + // We've reported the error, but we want to make sure that this + // problem doesn't bubble down and create additional, irrelevant + // errors. In this case, we're simply going to ignore the argument + // and any following arguments. The rest of the parameters will be + // inferred. + while args.next().is_some() {} } } } - (Some(_), None) => { + + (Some(&arg), None) => { // We should never be able to reach this point with well-formed input. - // Getting to this point means the user supplied more arguments than - // there are parameters. - args.next(); + // There are two situations in which we can encounter this issue. + // + // 1. The number of arguments is incorrect. In this case, an error + // will already have been emitted, and we can ignore it. This case + // also occurs when late-bound lifetime parameters are present, yet + // the lifetime arguments have also been explicitly specified by the + // user. + // 2. We've inferred some lifetimes, which have been provided later (i.e. + // after a type or const). We want to throw an error in this case. + + if arg_count_correct { + let kind = arg.descr(); + assert_eq!(kind, "lifetime"); + let provided = + force_infer_lt.expect("lifetimes ought to have been inferred"); + Self::generic_arg_mismatch_err(tcx.sess, provided, kind); + } + + break; } + (None, Some(¶m)) => { // If there are fewer arguments than parameters, it means // we're inferring the remaining arguments. substs.push(inferred_kind(Some(&substs), param, infer_args)); - args.next(); params.next(); } + (None, None) => break, } } @@ -595,7 +661,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Given the type/lifetime/const arguments provided to some path (along with /// an implicit `Self`, if this is a trait reference), returns the complete /// set of substitutions. This may involve applying defaulted type parameters. - /// Also returns back constriants on associated types. + /// Also returns back constraints on associated types. /// /// Example: /// @@ -631,7 +697,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_args: &'a hir::GenericArgs<'_>, infer_args: bool, self_ty: Option>, - ) -> (SubstsRef<'tcx>, Vec>, Option>) { + ) -> (SubstsRef<'tcx>, Vec>, Result<(), GenericArgCountMismatch>) + { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). @@ -657,7 +724,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert!(self_ty.is_none() && parent_substs.is_empty()); } - let (_, potential_assoc_types) = Self::check_generic_arg_count( + let arg_count_correct = Self::check_generic_arg_count( tcx, span, &generic_params, @@ -684,21 +751,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; let mut missing_type_params = vec![]; + let mut inferred_params = vec![]; let substs = Self::create_substs_for_generic_args( tcx, def_id, parent_substs, self_ty.is_some(), self_ty, + arg_count_correct.is_ok(), // Provide the generic args, and whether types should be inferred. - |_| (Some(generic_args), infer_args), + |did| { + if did == def_id { + (Some(generic_args), infer_args) + } else { + // The last component of this tuple is unimportant. + (None, false) + } + }, // Provide substitutions for parameters for which (valid) arguments have been provided. |param, arg| match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { self.ast_region_to_region(<, Some(param)).into() } (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { - self.ast_ty_to_ty(&ty).into() + if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) { + inferred_params.push(ty.span); + tcx.types.err.into() + } else { + self.ast_ty_to_ty(&ty).into() + } } (GenericParamDefKind::Const, GenericArg::Const(ct)) => { self.ast_const_to_const(&ct.value, tcx.type_of(param.def_id)).into() @@ -757,6 +838,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } }, ); + if !inferred_params.is_empty() { + // We always collect the spans for placeholder types when evaluating `fn`s, but we + // only want to emit an error complaining about them if infer types (`_`) are not + // allowed. `allow_ty_infer` gates this behavior. + crate::collect::placeholder_type_error( + tcx, + inferred_params[0], + &[], + inferred_params, + false, + ); + } self.complain_about_missing_type_params( missing_type_params, @@ -795,7 +888,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_params, self_ty, substs ); - (substs, assoc_bindings, potential_assoc_types) + (substs, assoc_bindings, arg_count_correct) } crate fn create_substs_for_associated_item( @@ -889,10 +982,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ), ); } - err.note(&format!( + err.note( "because of the default `Self` reference, type parameters must be \ - specified on object types" - )); + specified on object types", + ); err.emit(); } @@ -926,7 +1019,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, speculative: bool, - ) -> Option> { + ) -> Result<(), GenericArgCountMismatch> { let trait_def_id = trait_ref.trait_def_id(); debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); @@ -943,7 +1036,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { trait_ref.path.span }; - let (substs, assoc_bindings, potential_assoc_types) = self.create_substs_for_ast_trait_ref( + let (substs, assoc_bindings, arg_count_correct) = self.create_substs_for_ast_trait_ref( path_span, trait_def_id, self_ty, @@ -972,7 +1065,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { "instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}", trait_ref, bounds, poly_trait_ref ); - potential_assoc_types + + arg_count_correct } /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct @@ -1000,7 +1094,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { constness: Constness, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, - ) -> Option> { + ) -> Result<(), GenericArgCountMismatch> { self.instantiate_poly_trait_ref_inner( &poly_trait_ref.trait_ref, poly_trait_ref.span, @@ -1089,7 +1183,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_def_id: DefId, self_ty: Ty<'tcx>, trait_segment: &'a hir::PathSegment<'a>, - ) -> (SubstsRef<'tcx>, Vec>, Option>) { + ) -> (SubstsRef<'tcx>, Vec>, Result<(), GenericArgCountMismatch>) + { debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); @@ -1109,10 +1204,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_def_id: DefId, assoc_name: ast::Ident, ) -> bool { - self.tcx().associated_items(trait_def_id).iter().any(|item| { - item.kind == ty::AssocKind::Type - && self.tcx().hygienic_eq(assoc_name, item.ident, trait_def_id) - }) + self.tcx() + .associated_items(trait_def_id) + .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id) + .is_some() } // Returns `true` if a bounds list includes `?Sized`. @@ -1345,10 +1440,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let (assoc_ident, def_scope) = tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id); + + // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead + // of calling `filter_by_name_and_kind`. let assoc_ty = tcx .associated_items(candidate.def_id()) - .iter() - .find(|i| i.kind == ty::AssocKind::Type && i.ident.modern() == assoc_ident) + .filter_by_name_unhygienic(assoc_ident.name) + .find(|i| { + i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident + }) .expect("missing associated type"); if !assoc_ty.vis.is_accessible_from(def_scope, tcx) { @@ -1431,13 +1531,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; for trait_bound in trait_bounds.iter().rev() { - let cur_potential_assoc_types = self.instantiate_poly_trait_ref( + if let Err(GenericArgCountMismatch { + invalid_args: cur_potential_assoc_types, .. + }) = self.instantiate_poly_trait_ref( trait_bound, Constness::NotConst, dummy_self, &mut bounds, - ); - potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten()); + ) { + potential_assoc_types.extend(cur_potential_assoc_types.into_iter()); + } } // Expand trait aliases recursively and check that only one regular (non-auto) trait @@ -1513,7 +1616,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::Predicate::Trait(pred, _) => { associated_types.entry(span).or_default().extend( tcx.associated_items(pred.def_id()) - .iter() + .in_definition_order() .filter(|item| item.kind == ty::AssocKind::Type) .map(|item| item.def_id), ); @@ -1551,7 +1654,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } for (projection_bound, _) in &bounds.projection_bounds { - for (_, def_ids) in &mut associated_types { + for def_ids in associated_types.values_mut() { def_ids.remove(&projection_bound.projection_def_id()); } } @@ -1660,7 +1763,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { potential_assoc_types: Vec, trait_bounds: &[hir::PolyTraitRef<'_>], ) { - if !associated_types.values().any(|v| v.len() > 0) { + if !associated_types.values().any(|v| !v.is_empty()) { return; } let tcx = self.tcx(); @@ -1775,7 +1878,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { { let types: Vec<_> = assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect(); - let code = if snippet.ends_with(">") { + let code = if snippet.ends_with('>') { // The user wrote `Trait<'a>` or similar and we don't have a type we can // suggest, but at least we can clue them to the correct syntax // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the @@ -1968,14 +2071,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut where_bounds = vec![]; for bound in bounds { + let bound_id = bound.def_id(); let bound_span = self .tcx() - .associated_items(bound.def_id()) - .iter() - .find(|item| { - item.kind == ty::AssocKind::Type - && self.tcx().hygienic_eq(assoc_name, item.ident, bound.def_id()) - }) + .associated_items(bound_id) + .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, bound_id) .and_then(|item| self.tcx().hir().span_if_local(item.def_id)); if let Some(bound_span) = bound_span { @@ -2053,7 +2153,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); let all_candidate_names: Vec<_> = all_candidates() - .map(|r| self.tcx().associated_items(r.def_id())) + .map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) .flatten() .filter_map( |item| if item.kind == ty::AssocKind::Type { Some(item.ident.name) } else { None }, @@ -2199,10 +2299,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let trait_did = bound.def_id(); let (assoc_ident, def_scope) = tcx.adjust_ident_and_get_scope(assoc_ident, trait_did, hir_ref_id); + + // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead + // of calling `filter_by_name_and_kind`. let item = tcx .associated_items(trait_did) - .iter() - .find(|i| Namespace::from(i.kind) == Namespace::Type && i.ident.modern() == assoc_ident) + .in_definition_order() + .find(|i| { + i.kind.namespace() == Namespace::TypeNS + && i.ident.normalize_to_macros_2_0() == assoc_ident + }) .expect("missing associated type"); let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound); @@ -2356,10 +2462,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { break; } } - for binding in segment.generic_args().bindings { + + // Only emit the first error to avoid overloading the user with error messages. + if let [binding, ..] = segment.generic_args().bindings { has_err = true; Self::prohibit_assoc_ty_binding(self.tcx(), binding.span); - break; } } has_err @@ -2486,7 +2593,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Case 4. Reference to a method or associated const. - DefKind::Method | DefKind::AssocConst => { + DefKind::AssocFn | DefKind::AssocConst => { if segments.len() >= 2 { let generics = tcx.generics_of(def_id); path_segs.push(PathSeg(generics.parent.unwrap(), last - 1)); @@ -2740,6 +2847,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // mir. if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) { return c; + } else { + tcx.sess.delay_span_bug(expr.span, "ast_const_to_const: couldn't lit_to_const"); } } @@ -2820,18 +2929,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let tcx = self.tcx(); - // We proactively collect all the infered type params to emit a single error per fn def. + // We proactively collect all the inferred type params to emit a single error per fn def. let mut visitor = PlaceholderHirTyCollector::default(); for ty in decl.inputs { visitor.visit_ty(ty); } let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None)); let output_ty = match decl.output { - hir::FunctionRetTy::Return(ref output) => { + hir::FnRetTy::Return(ref output) => { visitor.visit_ty(output); self.ast_ty_to_ty(output) } - hir::FunctionRetTy::DefaultReturn(..) => tcx.mk_unit(), + hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(), }; debug!("ty_of_fn: output_ty={:?}", output_ty); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 686cdfbc089..20737b44e7c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -1,12 +1,12 @@ use crate::check::coercion::CoerceMany; use crate::check::{Diverges, Expectation, FnCtxt, Needs}; -use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc::traits::ObligationCauseCode; -use rustc::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause}; use rustc::ty::Ty; use rustc_hir as hir; use rustc_hir::ExprKind; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_span::Span; +use rustc_trait_selection::traits::ObligationCauseCode; +use rustc_trait_selection::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_match( diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index d436733d19a..2315b42aec5 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -1,17 +1,17 @@ use super::method::MethodCallee; use super::{FnCtxt, Needs, PlaceOp}; -use rustc::infer::{InferCtxt, InferOk}; -use rustc::session::DiagnosticMessageId; -use rustc::traits::{self, TraitEngine}; use rustc::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; use rustc::ty::{ToPredicate, TypeFoldable}; +use rustc_ast::ast::Ident; use rustc_errors::struct_span_err; use rustc_hir as hir; - +use rustc_infer::infer::{InferCtxt, InferOk}; +use rustc_session::DiagnosticMessageId; use rustc_span::Span; -use syntax::ast::Ident; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{self, TraitEngine}; use std::iter; diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index b33cc52b238..3f8019e64b2 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -3,18 +3,18 @@ use super::method::MethodCallee; use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag}; use crate::type_error_struct; -use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::{infer, traits}; +use rustc_ast::ast::Ident; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::{infer, traits}; use rustc_span::Span; use rustc_target::spec::abi; -use syntax::ast::Ident; /// Checks that it is legal to call methods of the trait corresponding /// to `trait_id` (this only cares about the trait, not the specific diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 909f40ee984..2875d38a996 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -31,23 +31,22 @@ use super::FnCtxt; use crate::hir::def_id::DefId; -use crate::lint; use crate::type_error_struct; use crate::util::common::ErrorReported; use rustc::middle::lang_items; -use rustc::session::Session; -use rustc::traits; -use rustc::traits::error_reporting::report_object_safety_error; -use rustc::traits::object_safety_violations; use rustc::ty::adjustment::AllowTwoPhase; use rustc::ty::cast::{CastKind, CastTy}; use rustc::ty::error::TypeError; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable}; +use rustc_ast::ast; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; +use rustc_session::lint; +use rustc_session::Session; use rustc_span::Span; -use syntax::ast; +use rustc_trait_selection::traits; +use rustc_trait_selection::traits::error_reporting::report_object_safety_error; /// Reifies a cast check to be checked once we have full type information for /// a function context. @@ -517,7 +516,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) { - let violations = object_safety_violations(fcx.tcx, did); + let violations = fcx.tcx.object_safety_violations(did); let mut err = report_object_safety_error(fcx.tcx, self.cast_span, did, violations); err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty))); err.emit(); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 396534b3cae..49b7a997311 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -4,18 +4,19 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes}; use crate::astconv::AstConv; use crate::middle::{lang_items, region}; -use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc::infer::LateBoundRegionConversionTime; -use rustc::infer::{InferOk, InferResult}; -use rustc::traits::error_reporting::ArgKind; -use rustc::traits::Obligation; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::InternalSubsts; use rustc::ty::{self, GenericParamDefKind, Ty}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::LateBoundRegionConversionTime; +use rustc_infer::infer::{InferOk, InferResult}; use rustc_span::source_map::Span; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits::error_reporting::ArgKind; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::Obligation; use std::cmp; use std::iter; @@ -248,7 +249,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if is_gen { // Check that we deduce the signature from the `<_ as std::ops::Generator>::Return` // associated item and not yield. - let return_assoc_item = self.tcx.associated_items(gen_trait)[1].def_id; + let return_assoc_item = + self.tcx.associated_items(gen_trait).in_definition_order().nth(1).unwrap().def_id; if return_assoc_item != projection.projection_def_id() { debug!("deduce_sig_from_projection: not return assoc item of generator"); return None; @@ -555,8 +557,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // First, convert the types that the user supplied (if any). let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a)); let supplied_return = match decl.output { - hir::FunctionRetTy::Return(ref output) => astconv.ast_ty_to_ty(&output), - hir::FunctionRetTy::DefaultReturn(_) => match body.generator_kind { + hir::FnRetTy::Return(ref output) => astconv.ast_ty_to_ty(&output), + hir::FnRetTy::DefaultReturn(_) => match body.generator_kind { // In the case of the async block that we create for a function body, // we expect the return type of the block to match that of the enclosing // function. @@ -673,7 +675,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The `Future` trait has only one associted item, `Output`, // so check that this is what we see. - let output_assoc_item = self.tcx.associated_items(future_trait)[0].def_id; + let output_assoc_item = + self.tcx.associated_items(future_trait).in_definition_order().next().unwrap().def_id; if output_assoc_item != predicate.projection_ty.item_def_id { span_bug!( cause_span, @@ -703,7 +706,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.types.err }); - if let hir::FunctionRetTy::Return(ref output) = decl.output { + if let hir::FnRetTy::Return(ref output) = decl.output { astconv.ast_ty_to_ty(&output); } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index bedef5042fd..b0d74651847 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -52,11 +52,6 @@ use crate::astconv::AstConv; use crate::check::{FnCtxt, Needs}; -use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc::infer::{Coercion, InferOk, InferResult}; -use rustc::session::parse::feature_err; -use rustc::traits::object_safety_violations; -use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, }; @@ -68,9 +63,15 @@ use rustc::ty::{self, Ty, TypeAndMut}; use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::{Coercion, InferOk, InferResult}; +use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{self, Span}; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; + use smallvec::{smallvec, SmallVec}; use std::ops::Deref; @@ -112,7 +113,7 @@ fn identity(_: Ty<'_>) -> Vec> { vec![] } -fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec> { +fn simple(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec> { move |target| vec![Adjustment { kind, target }] } @@ -1363,7 +1364,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx: &FnCtxt<'a, 'tcx>, expected: Ty<'tcx>, sp: Span, - fn_output: &hir::FunctionRetTy<'_>, + fn_output: &hir::FnRetTy<'_>, ) { let return_sp = fn_output.span(); err.span_label(return_sp, "expected because this return type..."); @@ -1389,7 +1390,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let has_impl = snippet_iter.next().map_or(false, |s| s == "impl"); // Only suggest `Box` if `Trait` in `impl Trait` is object safe. let mut is_object_safe = false; - if let hir::FunctionRetTy::Return(ty) = fn_output { + if let hir::FnRetTy::Return(ty) = fn_output { // Get the return type. if let hir::TyKind::Def(..) = ty.kind { let ty = AstConv::ast_ty_to_ty(fcx, ty); @@ -1404,7 +1405,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // Are of this `impl Trait`'s traits object safe? is_object_safe = bounds.iter().all(|bound| { bound.trait_def_id().map_or(false, |def_id| { - object_safety_violations(fcx.tcx, def_id).is_empty() + fcx.tcx.object_safety_violations(def_id).is_empty() }) }) } @@ -1430,7 +1431,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool { if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) { - if let hir::FunctionRetTy::Return(ty) = fn_decl.output { + if let hir::FnRetTy::Return(ty) = fn_decl.output { let ty = AstConv::ast_ty_to_ty(fcx, ty); if let ty::Dynamic(..) = ty.kind { return true; diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 414f80d84b6..a2832d92d4a 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -1,6 +1,3 @@ -use rustc::hir::map::Map; -use rustc::infer::{self, InferOk}; -use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::util::ExplicitSelf; @@ -11,7 +8,10 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; +use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_span::Span; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use super::{potentially_plural_count, FnCtxt, Inherited}; @@ -402,7 +402,7 @@ fn extract_spans_for_error_reporting<'a, 'tcx>( let tcx = infcx.tcx; let impl_m_hir_id = tcx.hir().as_local_hir_id(impl_m.def_id).unwrap(); let (impl_m_output, impl_m_iter) = match tcx.hir().expect_impl_item(impl_m_hir_id).kind { - ImplItemKind::Method(ref impl_m_sig, _) => { + ImplItemKind::Fn(ref impl_m_sig, _) => { (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()) } _ => bug!("{:?} is not a method", impl_m), @@ -412,8 +412,8 @@ fn extract_spans_for_error_reporting<'a, 'tcx>( TypeError::Mutability => { if let Some(trait_m_hir_id) = tcx.hir().as_local_hir_id(trait_m.def_id) { let trait_m_iter = match tcx.hir().expect_trait_item(trait_m_hir_id).kind { - TraitItemKind::Method(ref trait_m_sig, _) => trait_m_sig.decl.inputs.iter(), - _ => bug!("{:?} is not a TraitItemKind::Method", trait_m), + TraitItemKind::Fn(ref trait_m_sig, _) => trait_m_sig.decl.inputs.iter(), + _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m), }; impl_m_iter @@ -440,10 +440,10 @@ fn extract_spans_for_error_reporting<'a, 'tcx>( if let Some(trait_m_hir_id) = tcx.hir().as_local_hir_id(trait_m.def_id) { let (trait_m_output, trait_m_iter) = match tcx.hir().expect_trait_item(trait_m_hir_id).kind { - TraitItemKind::Method(ref trait_m_sig, _) => { + TraitItemKind::Fn(ref trait_m_sig, _) => { (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()) } - _ => bug!("{:?} is not a TraitItemKind::Method", trait_m), + _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m), }; let impl_iter = impl_sig.inputs().iter(); @@ -708,7 +708,7 @@ fn compare_number_of_method_arguments<'tcx>( let trait_m_hir_id = tcx.hir().as_local_hir_id(trait_m.def_id); let trait_span = if let Some(trait_id) = trait_m_hir_id { match tcx.hir().expect_trait_item(trait_id).kind { - TraitItemKind::Method(ref trait_m_sig, _) => { + TraitItemKind::Fn(ref trait_m_sig, _) => { let pos = if trait_number_args > 0 { trait_number_args - 1 } else { 0 }; if let Some(arg) = trait_m_sig.decl.inputs.get(pos) { Some(if pos == 0 { @@ -731,7 +731,7 @@ fn compare_number_of_method_arguments<'tcx>( }; let impl_m_hir_id = tcx.hir().as_local_hir_id(impl_m.def_id).unwrap(); let impl_span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind { - ImplItemKind::Method(ref impl_m_sig, _) => { + ImplItemKind::Fn(ref impl_m_sig, _) => { let pos = if impl_number_args > 0 { impl_number_args - 1 } else { 0 }; if let Some(arg) = impl_m_sig.decl.inputs.get(pos) { if pos == 0 { @@ -872,7 +872,7 @@ fn compare_synthetic_generics<'tcx>( let impl_m = tcx.hir().as_local_hir_id(impl_m.def_id)?; let impl_m = tcx.hir().impl_item(hir::ImplItemId { hir_id: impl_m }); let input_tys = match impl_m.kind { - hir::ImplItemKind::Method(ref sig, _) => sig.decl.inputs, + hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs, _ => unreachable!(), }; struct Visitor(Option, hir::def_id::DefId); @@ -889,10 +889,10 @@ fn compare_synthetic_generics<'tcx>( } } } - type Map = Map<'v>; + type Map = intravisit::ErasedMap<'v>; fn nested_visit_map( &mut self, - ) -> intravisit::NestedVisitorMap<'_, Self::Map> + ) -> intravisit::NestedVisitorMap { intravisit::NestedVisitorMap::None } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 4a98095ec89..0556c80e4f7 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -1,15 +1,17 @@ use crate::check::FnCtxt; -use rustc::infer::InferOk; -use rustc::traits::{self, ObligationCause}; +use rustc_infer::infer::InferOk; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_trait_selection::traits::{self, ObligationCause}; use rustc::ty::adjustment::AllowTwoPhase; use rustc::ty::{self, AssocItem, Ty}; +use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::{is_range_literal, print, Node}; use rustc_span::symbol::sym; use rustc_span::Span; -use syntax::util::parser::PREC_POSTFIX; use super::method::probe; @@ -43,7 +45,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, actual: Ty<'tcx>, ) -> Option> { - let cause = &self.misc(sp); + self.demand_suptype_with_origin(&self.misc(sp), expected, actual) + } + + pub fn demand_suptype_with_origin( + &self, + cause: &ObligationCause<'tcx>, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + ) -> Option> { match self.at(cause, self.param_env).sup(expected, actual) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); @@ -228,8 +238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // FIXME? Other potential candidate methods: `as_ref` and // `as_mut`? - .find(|a| a.check_name(sym::rustc_conversion_suggestion)) - .is_some() + .any(|a| a.check_name(sym::rustc_conversion_suggestion)) }); methods @@ -324,13 +333,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir_id: hir::HirId, sp: Span, ) -> bool { - let cm = self.sess().source_map(); + let sm = self.sess().source_map(); let parent_id = self.tcx.hir().get_parent_node(hir_id); if let Some(parent) = self.tcx.hir().find(parent_id) { // Account for fields if let Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) = parent { - if let Ok(src) = cm.span_to_snippet(sp) { + if let Ok(src) = sm.span_to_snippet(sp) { for field in *fields { if field.ident.as_str() == src && field.is_shorthand { return true; @@ -364,9 +373,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { checked_ty: Ty<'tcx>, expected: Ty<'tcx>, ) -> Option<(Span, &'static str, String)> { - let cm = self.sess().source_map(); + let sm = self.sess().source_map(); let sp = expr.span; - if !cm.span_to_filename(sp).is_real() { + if sm.is_imported(sp) { // Ignore if span is from within a macro #41858, #58298. We previously used the macro // call span, but that breaks down when the type error comes from multiple calls down. return None; @@ -388,7 +397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { - if let Ok(src) = cm.span_to_snippet(sp) { + if let Ok(src) = sm.span_to_snippet(sp) { if src.starts_with("b\"") { return Some(( sp, @@ -403,8 +412,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { - if let Ok(src) = cm.span_to_snippet(sp) { - if src.starts_with("\"") { + if let Ok(src) = sm.span_to_snippet(sp) { + if src.starts_with('"') { return Some(( sp, "consider adding a leading `b`", @@ -450,7 +459,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg_sp = arg.span; } } - if let Ok(src) = cm.span_to_snippet(sugg_sp) { + if let Ok(src) = sm.span_to_snippet(sugg_sp) { let needs_parens = match expr.kind { // parenthesize if needed (Issue #46756) hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, @@ -480,7 +489,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // | | // consider dereferencing here: `*opt` | // expected mutable reference, found enum `Option` - if let Ok(src) = cm.span_to_snippet(left_expr.span) { + if let Ok(src) = sm.span_to_snippet(left_expr.span) { return Some(( left_expr.span, "consider dereferencing here to assign to the mutable \ @@ -516,9 +525,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // We have `&T`, check if what was expected was `T`. If so, // we may want to suggest removing a `&`. - if !cm.span_to_filename(expr.span).is_real() { - if let Ok(code) = cm.span_to_snippet(sp) { - if code.chars().next() == Some('&') { + if sm.is_imported(expr.span) { + if let Ok(code) = sm.span_to_snippet(sp) { + if code.starts_with('&') { return Some(( sp, "consider removing the borrow", @@ -528,7 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } return None; } - if let Ok(code) = cm.span_to_snippet(expr.span) { + if let Ok(code) = sm.span_to_snippet(expr.span) { return Some((sp, "consider removing the borrow", code)); } } @@ -539,7 +548,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let item_def_id = self .tcx .associated_items(deref_trait) - .iter() + .in_definition_order() .find(|item| item.kind == ty::AssocKind::Type) .unwrap() .def_id; @@ -562,7 +571,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_copy = self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp); if is_copy && impls_deref { - if let Ok(code) = cm.span_to_snippet(sp) { + if let Ok(code) = sm.span_to_snippet(sp) { let message = if checked_ty.is_region_ptr() { "consider dereferencing the borrow" } else { @@ -594,7 +603,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(estebank): modify once we decide to suggest `as` casts return false; } - if !self.tcx.sess.source_map().span_to_filename(expr.span).is_real() { + if self.tcx.sess.source_map().is_imported(expr.span) { // Ignore if span is from within a macro. return false; } @@ -701,7 +710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // Remove fractional part from literal, for example `42.0f32` into `42` let src = src.trim_end_matches(&checked_ty.to_string()); - src.split(".").next().unwrap() + src.split('.').next().unwrap() } else { src.trim_end_matches(&checked_ty.to_string()) }, diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 32773e2ed80..e48ebbbb235 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -2,17 +2,19 @@ use crate::check::regionck::RegionCtxt; use crate::hir; use crate::hir::def_id::DefId; use crate::util::common::ErrorReported; -use rustc::infer::outlives::env::OutlivesEnvironment; -use rustc::infer::{InferOk, SuppressRegionErrors}; use rustc::middle::region; -use rustc::traits::{ObligationCause, TraitEngine, TraitEngineExt}; use rustc::ty::error::TypeError; use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc::ty::subst::{Subst, SubstsRef}; use rustc::ty::{self, Predicate, Ty, TyCtxt}; use rustc_errors::struct_span_err; - +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::{InferOk, RegionckMode, TyCtxtInferExt}; +use rustc_infer::traits::TraitEngineExt as _; use rustc_span::Span; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::query::dropck_outlives::AtExt; +use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt}; /// This function confirms that the `Drop` implementation identified by /// `drop_impl_did` is not any more specialized than the type it is @@ -137,7 +139,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( drop_impl_did, ®ion_scope_tree, &outlives_env, - SuppressRegionErrors::default(), + RegionckMode::default(), ); Ok(()) }) diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 90b7b300da9..617c54a738e 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -17,26 +17,27 @@ use crate::check::TupleArgumentsFlag::DontTupleArguments; use crate::type_error_struct; use crate::util::common::ErrorReported; -use rustc::infer; -use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::middle::lang_items; -use rustc::traits::{self, ObligationCauseCode}; +use rustc::mir::interpret::ErrorHandled; use rustc::ty; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::Ty; use rustc::ty::TypeFoldable; use rustc::ty::{AdtKind, Visibility}; +use rustc_ast::ast; +use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ExprKind, QPath}; +use rustc_infer::infer; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Symbol}; -use syntax::ast; -use syntax::util::lev_distance::find_best_match_for_name; +use rustc_trait_selection::traits::{self, ObligationCauseCode}; use std::fmt::Display; @@ -404,7 +405,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let needs = Needs::maybe_mut_place(mutbl); let ty = self.check_expr_with_expectation_and_needs(&oprnd, hint, needs); - let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl }; + let tm = ty::TypeAndMut { ty, mutbl }; match kind { _ if tm.ty.references_error() => self.tcx.types.err, hir::BorrowKind::Raw => { @@ -1012,6 +1013,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(self.to_const(count, tcx.type_of(count_def_id))) } else { tcx.const_eval_poly(count_def_id) + .map(|val| ty::Const::from_value(tcx, val, tcx.type_of(count_def_id))) }; let uty = match expected { @@ -1038,11 +1040,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if element_ty.references_error() { - tcx.types.err - } else if let Ok(count) = count { - tcx.mk_ty(ty::Array(t, count)) - } else { - tcx.types.err + return tcx.types.err; + } + match count { + Ok(count) => tcx.mk_ty(ty::Array(t, count)), + Err(ErrorHandled::TooGeneric) => { + self.tcx.sess.span_err( + tcx.def_span(count_def_id), + "array lengths can't depend on generic parameters", + ); + tcx.types.err + } + Err(ErrorHandled::Reported) => tcx.types.err, } } @@ -1194,7 +1203,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .fields .iter() .enumerate() - .map(|(i, field)| (field.ident.modern(), (i, field))) + .map(|(i, field)| (field.ident.normalize_to_macros_2_0(), (i, field))) .collect::>(); let mut seen_fields = FxHashMap::default(); @@ -1311,6 +1320,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty_span: Span, ) { if variant.recovered { + self.set_tainted_by_errors(); return; } let mut err = self.type_error_struct_with_diag( @@ -1459,7 +1469,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope(field, base_def.did, self.body_id); let fields = &base_def.non_enum_variant().fields; - if let Some(index) = fields.iter().position(|f| f.ident.modern() == ident) { + if let Some(index) = + fields.iter().position(|f| f.ident.normalize_to_macros_2_0() == ident) + { let field = &fields[index]; let field_ty = self.field_ty(expr.span, field, substs); // Save the index of all fields regardless of their visibility in case @@ -1619,7 +1631,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn point_at_param_definition(&self, err: &mut DiagnosticBuilder<'_>, param: ty::ParamTy) { - let generics = self.tcx.generics_of(self.body_id.owner_def_id()); + let generics = self.tcx.generics_of(self.body_id.owner.to_def_id()); let generic_param = generics.type_param(¶m, self.tcx); if let ty::GenericParamDefKind::Type { synthetic: Some(..), .. } = generic_param.kind { return; diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 50692e0f104..cdf68256a7a 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -4,7 +4,6 @@ //! types computed here. use super::FnCtxt; -use rustc::hir::map::Map; use rustc::middle::region::{self, YieldData}; use rustc::ty::{self, Ty}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -209,9 +208,9 @@ pub fn resolve_interior<'a, 'tcx>( // librustc/middle/region.rs since `expr_count` is compared against the results // there. impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { - type Map = Map<'tcx>; + type Map = intravisit::ErasedMap<'tcx>; - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } @@ -237,7 +236,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // ZST in a temporary, so skip its type, just in case it // can significantly complicate the generator type. Res::Def(DefKind::Fn, _) - | Res::Def(DefKind::Method, _) + | Res::Def(DefKind::AssocFn, _) | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => { // NOTE(eddyb) this assumes a path expression has // no nested expressions to keep track of. diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 3572eda5c13..dd5e5726e83 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -147,9 +147,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { ), "rustc_peek" => (1, vec![param(0)], param(0)), "caller_location" => (0, vec![], tcx.caller_location_ty()), - "panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()), - "init" => (1, Vec::new(), param(0)), - "uninit" => (1, Vec::new(), param(0)), + "assert_inhabited" | "assert_zero_valid" | "assert_uninit_valid" => { + (1, Vec::new(), tcx.mk_unit()) + } "forget" => (1, vec![param(0)], tcx.mk_unit()), "transmute" => (2, vec![param(0)], param(1)), "move_val_init" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), @@ -297,14 +297,25 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { "try" => { let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); - let fn_ty = ty::Binder::bind(tcx.mk_fn_sig( + let try_fn_ty = ty::Binder::bind(tcx.mk_fn_sig( iter::once(mut_u8), tcx.mk_unit(), false, hir::Unsafety::Normal, Abi::Rust, )); - (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32) + let catch_fn_ty = ty::Binder::bind(tcx.mk_fn_sig( + [mut_u8, mut_u8].iter().cloned(), + tcx.mk_unit(), + false, + hir::Unsafety::Normal, + Abi::Rust, + )); + ( + 0, + vec![tcx.mk_fn_ptr(try_fn_ty), mut_u8, tcx.mk_fn_ptr(catch_fn_ty)], + tcx.types.i32, + ) } "va_start" | "va_end" => match mk_va_list_ty(hir::Mutability::Mut) { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index eee9dc99d35..48c72567b5c 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -4,15 +4,15 @@ use crate::astconv::AstConv; use crate::check::{callee, FnCtxt, Needs, PlaceOp}; use crate::hir::def_id::DefId; use crate::hir::GenericArg; -use rustc::infer::{self, InferOk}; -use rustc::traits; use rustc::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast}; use rustc::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::{Subst, SubstsRef}; use rustc::ty::{self, GenericParamDefKind, Ty}; use rustc_hir as hir; +use rustc_infer::infer::{self, InferOk}; use rustc_span::Span; +use rustc_trait_selection::traits; use std::ops::Deref; @@ -299,7 +299,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let generics = self.tcx.generics_of(pick.item.def_id); - AstConv::check_generic_arg_count_for_call( + let arg_count_correct = AstConv::check_generic_arg_count_for_call( self.tcx, self.span, &generics, &seg, true, // `is_method_call` ); @@ -313,10 +313,16 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { parent_substs, false, None, + arg_count_correct.is_ok(), // Provide the generic args, and whether types should be inferred. - |_| { - // The last argument of the returned tuple here is unimportant. - if let Some(ref data) = seg.args { (Some(data), false) } else { (None, false) } + |def_id| { + // The last component of the returned tuple here is unimportant. + if def_id == pick.item.def_id { + if let Some(ref data) = seg.args { + return (Some(data), false); + } + } + (None, false) }, // Provide substitutions for parameters for which (valid) arguments have been provided. |param, arg| match (¶m.kind, arg) { diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index c3e15c507b3..3cf7b65e30f 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -1,6 +1,6 @@ -//! Method lookup: the secret sauce of Rust. See the [rustc guide] for more information. +//! Method lookup: the secret sauce of Rust. See the [rustc dev guide] for more information. //! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/method-lookup.html +//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html mod confirm; pub mod probe; @@ -11,20 +11,20 @@ pub use self::CandidateSource::*; pub use self::MethodError::*; use crate::check::FnCtxt; -use crate::namespace::Namespace; -use rustc::infer::{self, InferOk}; -use rustc::traits; use rustc::ty::subst::Subst; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::ty::GenericParamDefKind; -use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable, WithConstness}; +use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness}; +use rustc_ast::ast; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind}; +use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; +use rustc_infer::infer::{self, InferOk}; use rustc_span::Span; -use syntax::ast; +use rustc_trait_selection::traits; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use self::probe::{IsSuggestion, ProbeScope}; @@ -68,7 +68,7 @@ pub enum MethodError<'tcx> { // could lead to matches if satisfied, and a list of not-in-scope traits which may work. pub struct NoMatchData<'tcx> { pub static_candidates: Vec, - pub unsatisfied_predicates: Vec>, + pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option>)>, pub out_of_scope_traits: Vec, pub lev_candidate: Option, pub mode: probe::Mode, @@ -77,7 +77,7 @@ pub struct NoMatchData<'tcx> { impl<'tcx> NoMatchData<'tcx> { pub fn new( static_candidates: Vec, - unsatisfied_predicates: Vec>, + unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option>)>, out_of_scope_traits: Vec, lev_candidate: Option, mode: probe::Mode, @@ -342,7 +342,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Trait must have a method named `m_name` and it should not have // type parameters or early-bound regions. let tcx = self.tcx; - let method_item = match self.associated_item(trait_def_id, m_name, Namespace::Value) { + let method_item = match self.associated_item(trait_def_id, m_name, Namespace::ValueNS) { Some(method_item) => method_item, None => { tcx.sess.delay_span_bug( @@ -460,12 +460,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ProbeScope::TraitsInScope, )?; debug!("resolve_ufcs: pick={:?}", pick); - for import_id in pick.import_ids { - let import_def_id = tcx.hir().local_def_id(import_id); - debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id); - Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports) - .unwrap() - .insert(import_def_id); + { + let mut tables = self.tables.borrow_mut(); + let used_trait_imports = Lrc::get_mut(&mut tables.used_trait_imports).unwrap(); + for import_id in pick.import_ids { + let import_def_id = tcx.hir().local_def_id(import_id); + debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id); + used_trait_imports.insert(import_def_id); + } } let def_kind = pick.item.def_kind(); @@ -484,11 +486,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Option { self.tcx .associated_items(def_id) - .iter() - .find(|item| { - Namespace::from(item.kind) == ns - && self.tcx.hygienic_eq(item_name, item.ident, def_id) - }) + .find_by_name_and_namespace(self.tcx, item_name, ns, def_id) .copied() } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 760b6487045..45b1c7d6ea7 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -7,37 +7,39 @@ use crate::check::autoderef::{self, Autoderef}; use crate::check::FnCtxt; use crate::hir::def::DefKind; use crate::hir::def_id::DefId; -use crate::namespace::Namespace; - -use rustc::infer::canonical::OriginalQueryValues; -use rustc::infer::canonical::{Canonical, QueryResponse}; -use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc::infer::{self, InferOk}; -use rustc::lint; + use rustc::middle::stability; -use rustc::session::config::nightly_options; -use rustc::traits::query::method_autoderef::MethodAutoderefBadTy; -use rustc::traits::query::method_autoderef::{CandidateStep, MethodAutoderefStepsResult}; -use rustc::traits::query::CanonicalTyGoal; -use rustc::traits::{self, ObligationCause}; use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc::ty::GenericParamDefKind; use rustc::ty::{ - self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, - WithConstness, + self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; +use rustc_ast::ast; +use rustc_ast::util::lev_distance::{find_best_match_for_name, lev_distance}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_errors::struct_span_err; use rustc_hir as hir; +use rustc_hir::def::Namespace; +use rustc_infer::infer::canonical::OriginalQueryValues; +use rustc_infer::infer::canonical::{Canonical, QueryResponse}; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; +use rustc_session::config::nightly_options; +use rustc_session::lint; use rustc_span::{symbol::Symbol, Span, DUMMY_SP}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; +use rustc_trait_selection::traits::query::method_autoderef::{ + CandidateStep, MethodAutoderefStepsResult, +}; +use rustc_trait_selection::traits::query::CanonicalTyGoal; +use rustc_trait_selection::traits::{self, ObligationCause}; use std::cmp::max; use std::iter; use std::mem; use std::ops::Deref; -use syntax::ast; -use syntax::util::lev_distance::{find_best_match_for_name, lev_distance}; use smallvec::{smallvec, SmallVec}; @@ -78,7 +80,7 @@ struct ProbeContext<'a, 'tcx> { /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used /// for error reporting - unsatisfied_predicates: Vec>, + unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option>)>, is_suggestion: IsSuggestion, } @@ -573,7 +575,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } fn assemble_inherent_candidates(&mut self) { - let steps = self.steps.clone(); + let steps = Lrc::clone(&self.steps); for step in steps.iter() { self.assemble_probe(&step.self_ty); } @@ -636,87 +638,51 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.assemble_inherent_impl_for_primitive(lang_def_id); } ty::Slice(_) => { - let lang_def_id = lang_items.slice_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - - let lang_def_id = lang_items.slice_u8_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - - let lang_def_id = lang_items.slice_alloc_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - - let lang_def_id = lang_items.slice_u8_alloc_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Not }) => { - let lang_def_id = lang_items.const_ptr_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Mut }) => { - let lang_def_id = lang_items.mut_ptr_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::Int(ast::IntTy::I8) => { - let lang_def_id = lang_items.i8_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::Int(ast::IntTy::I16) => { - let lang_def_id = lang_items.i16_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::Int(ast::IntTy::I32) => { - let lang_def_id = lang_items.i32_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::Int(ast::IntTy::I64) => { - let lang_def_id = lang_items.i64_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::Int(ast::IntTy::I128) => { - let lang_def_id = lang_items.i128_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::Int(ast::IntTy::Isize) => { - let lang_def_id = lang_items.isize_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::Uint(ast::UintTy::U8) => { - let lang_def_id = lang_items.u8_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::Uint(ast::UintTy::U16) => { - let lang_def_id = lang_items.u16_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::Uint(ast::UintTy::U32) => { - let lang_def_id = lang_items.u32_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - } - ty::Uint(ast::UintTy::U64) => { - let lang_def_id = lang_items.u64_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + for &lang_def_id in &[ + lang_items.slice_impl(), + lang_items.slice_u8_impl(), + lang_items.slice_alloc_impl(), + lang_items.slice_u8_alloc_impl(), + ] { + self.assemble_inherent_impl_for_primitive(lang_def_id); + } } - ty::Uint(ast::UintTy::U128) => { - let lang_def_id = lang_items.u128_impl(); + ty::RawPtr(ty::TypeAndMut { ty: _, mutbl }) => { + let lang_def_id = match mutbl { + hir::Mutability::Not => lang_items.const_ptr_impl(), + hir::Mutability::Mut => lang_items.mut_ptr_impl(), + }; self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::Uint(ast::UintTy::Usize) => { - let lang_def_id = lang_items.usize_impl(); + ty::Int(i) => { + let lang_def_id = match i { + ast::IntTy::I8 => lang_items.i8_impl(), + ast::IntTy::I16 => lang_items.i16_impl(), + ast::IntTy::I32 => lang_items.i32_impl(), + ast::IntTy::I64 => lang_items.i64_impl(), + ast::IntTy::I128 => lang_items.i128_impl(), + ast::IntTy::Isize => lang_items.isize_impl(), + }; self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::Float(ast::FloatTy::F32) => { - let lang_def_id = lang_items.f32_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - - let lang_def_id = lang_items.f32_runtime_impl(); + ty::Uint(i) => { + let lang_def_id = match i { + ast::UintTy::U8 => lang_items.u8_impl(), + ast::UintTy::U16 => lang_items.u16_impl(), + ast::UintTy::U32 => lang_items.u32_impl(), + ast::UintTy::U64 => lang_items.u64_impl(), + ast::UintTy::U128 => lang_items.u128_impl(), + ast::UintTy::Usize => lang_items.usize_impl(), + }; self.assemble_inherent_impl_for_primitive(lang_def_id); } - ty::Float(ast::FloatTy::F64) => { - let lang_def_id = lang_items.f64_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); - - let lang_def_id = lang_items.f64_runtime_impl(); - self.assemble_inherent_impl_for_primitive(lang_def_id); + ty::Float(f) => { + let (lang_def_id1, lang_def_id2) = match f { + ast::FloatTy::F32 => (lang_items.f32_impl(), lang_items.f32_runtime_impl()), + ast::FloatTy::F64 => (lang_items.f64_impl(), lang_items.f64_runtime_impl()), + }; + self.assemble_inherent_impl_for_primitive(lang_def_id1); + self.assemble_inherent_impl_for_primitive(lang_def_id2); } _ => {} } @@ -902,13 +868,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { for trait_candidate in applicable_traits.iter() { let trait_did = trait_candidate.def_id; if duplicates.insert(trait_did) { - let import_ids = trait_candidate - .import_ids - .iter() - .map(|node_id| self.fcx.tcx.hir().node_to_hir_id(*node_id)) - .collect(); - let result = - self.assemble_extension_candidates_for_trait(import_ids, trait_did); + let result = self.assemble_extension_candidates_for_trait( + &trait_candidate.import_ids, + trait_did, + ); result?; } } @@ -920,7 +883,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let mut duplicates = FxHashSet::default(); for trait_info in suggest::all_traits(self.tcx) { if duplicates.insert(trait_info.def_id) { - self.assemble_extension_candidates_for_trait(smallvec![], trait_info.def_id)?; + self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id)?; } } Ok(()) @@ -959,7 +922,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn assemble_extension_candidates_for_trait( &mut self, - import_ids: SmallVec<[hir::HirId; 1]>, + import_ids: &SmallVec<[hir::HirId; 1]>, trait_def_id: DefId, ) -> Result<(), MethodError<'tcx>> { debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); @@ -1044,7 +1007,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return r; } - debug!("pick: actual search failed, assemble diagnotics"); + debug!("pick: actual search failed, assemble diagnostics"); let static_candidates = mem::take(&mut self.static_candidates); let private_candidate = self.private_candidate.take(); @@ -1227,7 +1190,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, self_ty: Ty<'tcx>, probes: ProbesIter, - possibly_unsatisfied_predicates: &mut Vec>, + possibly_unsatisfied_predicates: &mut Vec<( + ty::Predicate<'tcx>, + Option>, + )>, unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>, ) -> Option> where @@ -1346,7 +1312,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { &self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>, - possibly_unsatisfied_predicates: &mut Vec>, + possibly_unsatisfied_predicates: &mut Vec<( + ty::Predicate<'tcx>, + Option>, + )>, ) -> ProbeResult { debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe); @@ -1401,21 +1370,44 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let predicate = trait_ref.without_const().to_predicate(); let obligation = traits::Obligation::new(cause, self.param_env, predicate); if !self.predicate_may_hold(&obligation) { - if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) { + result = ProbeResult::NoMatch; + if self.probe(|_| { + match self.select_trait_candidate(trait_ref) { + Err(_) => return true, + Ok(Some(vtable)) + if !vtable.borrow_nested_obligations().is_empty() => + { + for obligation in vtable.borrow_nested_obligations() { + // Determine exactly which obligation wasn't met, so + // that we can give more context in the error. + if !self.predicate_may_hold(&obligation) { + let o = self.resolve_vars_if_possible(obligation); + let predicate = + self.resolve_vars_if_possible(&predicate); + let p = if predicate == o.predicate { + // Avoid "`MyStruct: Foo` which is required by + // `MyStruct: Foo`" in E0599. + None + } else { + Some(predicate) + }; + possibly_unsatisfied_predicates.push((o.predicate, p)); + } + } + } + _ => { + // Some nested subobligation of this predicate + // failed. + let predicate = self.resolve_vars_if_possible(&predicate); + possibly_unsatisfied_predicates.push((predicate, None)); + } + } + false + }) { // This candidate's primary obligation doesn't even // select - don't bother registering anything in // `potentially_unsatisfied_predicates`. return ProbeResult::NoMatch; - } else { - // Some nested subobligation of this predicate - // failed. - // - // FIXME: try to find the exact nested subobligation - // and point at it rather than reporting the entire - // trait-ref? - result = ProbeResult::NoMatch; - let trait_ref = self.resolve_vars_if_possible(&trait_ref); - possibly_unsatisfied_predicates.push(trait_ref); } } vec![] @@ -1432,9 +1424,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let o = self.resolve_vars_if_possible(&o); if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; - if let &ty::Predicate::Trait(ref pred, _) = &o.predicate { - possibly_unsatisfied_predicates.push(pred.skip_binder().trait_ref); - } + possibly_unsatisfied_predicates.push((o.predicate, None)); } } @@ -1527,21 +1517,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let method_names = pcx.candidate_method_names(); pcx.allow_similar_names = false; - let applicable_close_candidates: Vec = - method_names - .iter() - .filter_map(|&method_name| { - pcx.reset(); - pcx.method_name = Some(method_name); - pcx.assemble_inherent_candidates(); - pcx.assemble_extension_candidates_for_traits_in_scope(hir::DUMMY_HIR_ID) - .map_or(None, |_| { - pcx.pick_core() - .and_then(|pick| pick.ok()) - .and_then(|pick| Some(pick.item)) - }) - }) - .collect(); + let applicable_close_candidates: Vec = method_names + .iter() + .filter_map(|&method_name| { + pcx.reset(); + pcx.method_name = Some(method_name); + pcx.assemble_inherent_candidates(); + pcx.assemble_extension_candidates_for_traits_in_scope(hir::DUMMY_HIR_ID) + .map_or(None, |_| { + pcx.pick_core().and_then(|pick| pick.ok()).map(|pick| pick.item) + }) + }) + .collect(); if applicable_close_candidates.is_empty() { Ok(None) @@ -1699,20 +1686,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let max_dist = max(name.as_str().len(), 3) / 3; self.tcx .associated_items(def_id) - .iter() + .in_definition_order() .filter(|x| { let dist = lev_distance(&*name.as_str(), &x.ident.as_str()); - Namespace::from(x.kind) == Namespace::Value && dist > 0 && dist <= max_dist + x.kind.namespace() == Namespace::ValueNS && dist > 0 && dist <= max_dist }) .copied() .collect() } else { self.fcx - .associated_item(def_id, name, Namespace::Value) + .associated_item(def_id, name, Namespace::ValueNS) .map_or(Vec::new(), |x| vec![x]) } } else { - self.tcx.associated_items(def_id).to_vec() + self.tcx.associated_items(def_id).in_definition_order().copied().collect() } } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 789bac2705b..2f0eb5e0670 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -3,23 +3,23 @@ use crate::check::FnCtxt; use crate::middle::lang_items::FnOnceTraitLangItem; -use crate::namespace::Namespace; use rustc::hir::map as hir_map; -use rustc::hir::map::Map; -use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc::traits::Obligation; use rustc::ty::print::with_crate_prefix; use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_data_structures::fx::FxHashSet; +use rustc_ast::ast; +use rustc_ast::util::lev_distance; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::intravisit; use rustc_hir::{ExprKind, Node, QPath}; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_span::symbol::kw; use rustc_span::{source_map, FileName, Span}; -use syntax::ast; -use syntax::util::lev_distance; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::Obligation; use std::cmp::Ordering; @@ -97,13 +97,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Provide the best span we can. Use the item, if local to crate, else // the impl, if local to crate (item may be defaulted), else nothing. let item = match self - .associated_item(impl_did, item_name, Namespace::Value) + .associated_item(impl_did, item_name, Namespace::ValueNS) .or_else(|| { let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?; self.associated_item( impl_trait_ref.def_id, item_name, - Namespace::Value, + Namespace::ValueNS, ) }) { Some(item) => item, @@ -167,7 +167,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .skip_binder() .get(0) .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr()) - .map(|ty| *ty) + .copied() .unwrap_or(rcvr_ty), }; print_disambiguation_help( @@ -185,7 +185,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } CandidateSource::TraitSource(trait_did) => { let item = - match self.associated_item(trait_did, item_name, Namespace::Value) { + match self.associated_item(trait_did, item_name, Namespace::ValueNS) { Some(item) => item, None => continue, }; @@ -264,7 +264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // be used exists at all, and the type is an ambiguous numeric type // ({integer}/{float}). let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| { - self.associated_item(info.def_id, item_name, Namespace::Value) + self.associated_item(info.def_id, item_name, Namespace::ValueNS) }); if let (true, false, SelfSource::MethodCall(expr), Some(_)) = ( actual.is_numeric(), @@ -427,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); if let Some((field, field_ty)) = field_receiver { - let scope = self.tcx.hir().get_module_parent(self.body_id); + let scope = self.tcx.parent_module(self.body_id).to_def_id(); let is_accessible = field.vis.is_accessible_from(scope, self.tcx); if is_accessible { @@ -497,7 +497,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !static_sources.is_empty() { err.note( "found the following associated functions; to be used as methods, \ - functions must have a `self` parameter", + functions must have a `self` parameter", ); err.span_label(span, "this is an associated function, not a method"); } @@ -535,22 +535,162 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { report_candidates(span, &mut err, static_sources, sugg_span); } + let mut restrict_type_params = false; if !unsatisfied_predicates.is_empty() { + let def_span = + |def_id| self.tcx.sess.source_map().def_span(self.tcx.def_span(def_id)); + let mut type_params = FxHashMap::default(); + let mut bound_spans = vec![]; + let mut collect_type_param_suggestions = + |self_ty: Ty<'_>, parent_pred: &ty::Predicate<'_>, obligation: &str| { + if let (ty::Param(_), ty::Predicate::Trait(p, _)) = + (&self_ty.kind, parent_pred) + { + if let ty::Adt(def, _) = p.skip_binder().trait_ref.self_ty().kind { + let node = self + .tcx + .hir() + .as_local_hir_id(def.did) + .map(|id| self.tcx.hir().get(id)); + match node { + Some(hir::Node::Item(hir::Item { kind, .. })) => { + if let Some(g) = kind.generics() { + let key = match &g.where_clause.predicates[..] { + [.., pred] => { + (pred.span().shrink_to_hi(), false) + } + [] => ( + g.where_clause + .span_for_predicates_or_empty_place(), + true, + ), + }; + type_params + .entry(key) + .or_insert_with(FxHashSet::default) + .insert(obligation.to_owned()); + } + } + _ => {} + } + } + } + }; + let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| { + let msg = format!( + "doesn't satisfy `{}`", + if obligation.len() > 50 { quiet } else { obligation } + ); + match &self_ty.kind { + // Point at the type that couldn't satisfy the bound. + ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)), + // Point at the trait object that couldn't satisfy the bound. + ty::Dynamic(preds, _) => { + for pred in *preds.skip_binder() { + match pred { + ty::ExistentialPredicate::Trait(tr) => { + bound_spans.push((def_span(tr.def_id), msg.clone())) + } + ty::ExistentialPredicate::Projection(_) + | ty::ExistentialPredicate::AutoTrait(_) => {} + } + } + } + // Point at the closure that couldn't satisfy the bound. + ty::Closure(def_id, _) => bound_spans + .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))), + _ => {} + } + }; + let mut format_pred = |pred| { + match pred { + ty::Predicate::Projection(pred) => { + // `::Item = String`. + let trait_ref = + pred.skip_binder().projection_ty.trait_ref(self.tcx); + let assoc = self + .tcx + .associated_item(pred.skip_binder().projection_ty.item_def_id); + let ty = pred.skip_binder().ty; + let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty); + let quiet = format!( + "<_ as {}>::{} = {}", + trait_ref.print_only_trait_path(), + assoc.ident, + ty + ); + bound_span_label(trait_ref.self_ty(), &obligation, &quiet); + Some((obligation, trait_ref.self_ty())) + } + ty::Predicate::Trait(poly_trait_ref, _) => { + let p = poly_trait_ref.skip_binder().trait_ref; + let self_ty = p.self_ty(); + let path = p.print_only_trait_path(); + let obligation = format!("{}: {}", self_ty, path); + let quiet = format!("_: {}", path); + bound_span_label(self_ty, &obligation, &quiet); + Some((obligation, self_ty)) + } + _ => None, + } + }; let mut bound_list = unsatisfied_predicates .iter() - .map(|p| format!("`{} : {}`", p.self_ty(), p.print_only_trait_path())) - .collect::>(); - bound_list.sort(); - bound_list.dedup(); // #35677 - let bound_list = bound_list.join("\n"); - err.note(&format!( - "the method `{}` exists but the following trait bounds \ - were not satisfied:\n{}", - item_name, bound_list - )); + .filter_map(|(pred, parent_pred)| { + format_pred(*pred).map(|(p, self_ty)| match parent_pred { + None => format!("`{}`", p), + Some(parent_pred) => match format_pred(*parent_pred) { + None => format!("`{}`", p), + Some((parent_p, _)) => { + collect_type_param_suggestions(self_ty, parent_pred, &p); + format!("`{}`\nwhich is required by `{}`", p, parent_p) + } + }, + }) + }) + .enumerate() + .collect::>(); + for ((span, empty_where), obligations) in type_params.into_iter() { + restrict_type_params = true; + err.span_suggestion_verbose( + span, + &format!( + "consider restricting the type parameter{s} to satisfy the \ + trait bound{s}", + s = pluralize!(obligations.len()) + ), + format!( + "{} {}", + if empty_where { " where" } else { "," }, + obligations.into_iter().collect::>().join(", ") + ), + Applicability::MaybeIncorrect, + ); + } + + bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically. + bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677 + bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order. + bound_spans.sort(); + bound_spans.dedup(); + for (span, msg) in bound_spans.into_iter() { + err.span_label(span, &msg); + } + if !bound_list.is_empty() { + let bound_list = bound_list + .into_iter() + .map(|(_, path)| path) + .collect::>() + .join("\n"); + err.note(&format!( + "the method `{}` exists but the following trait bounds were not \ + satisfied:\n{}", + item_name, bound_list + )); + } } - if actual.is_numeric() && actual.is_fresh() { + if actual.is_numeric() && actual.is_fresh() || restrict_type_params { } else { self.suggest_traits_to_import( &mut err, @@ -559,6 +699,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name, source, out_of_scope_traits, + &unsatisfied_predicates, ); } @@ -686,8 +827,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut msg: String, candidates: Vec, ) { - let module_did = self.tcx.hir().get_module_parent(self.body_id); - let module_id = self.tcx.hir().as_local_hir_id(module_did).unwrap(); + let module_did = self.tcx.parent_module(self.body_id); + let module_id = self.tcx.hir().as_local_hir_id(module_did.to_def_id()).unwrap(); let krate = self.tcx.hir().krate(); let (span, found_use) = UsePlacementFinder::check(self.tcx, krate, module_id); if let Some(span) = span { @@ -758,6 +899,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name: ast::Ident, source: SelfSource<'b>, valid_out_of_scope_traits: Vec, + unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option>)], ) { if self.suggest_valid_traits(err, valid_out_of_scope_traits) { return; @@ -765,6 +907,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source); + let mut arbitrary_rcvr = vec![]; // There are no traits implemented, so lets suggest some traits to // implement, by finding ones that have the item name, and are // legal to implement. @@ -777,16 +920,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this isn't perfect (that is, there are cases when // implementing a trait would be legal but is rejected // here). - (type_is_local || info.def_id.is_local()) + !unsatisfied_predicates.iter().any(|(p, _)| match p { + // Hide traits if they are present in predicates as they can be fixed without + // having to implement them. + ty::Predicate::Trait(t, _) => t.def_id() != info.def_id, + ty::Predicate::Projection(p) => p.item_def_id() != info.def_id, + _ => true, + }) && (type_is_local || info.def_id.is_local()) && self - .associated_item(info.def_id, item_name, Namespace::Value) + .associated_item(info.def_id, item_name, Namespace::ValueNS) .filter(|item| { + if let ty::AssocKind::Method = item.kind { + let id = self.tcx.hir().as_local_hir_id(item.def_id); + if let Some(hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(fn_sig, method), + .. + })) = id.map(|id| self.tcx.hir().get(id)) + { + let self_first_arg = match method { + hir::TraitFn::Required([ident, ..]) => { + ident.name == kw::SelfLower + } + hir::TraitFn::Provided(body_id) => { + match &self.tcx.hir().body(*body_id).params[..] { + [hir::Param { + pat: + hir::Pat { + kind: + hir::PatKind::Binding( + _, + _, + ident, + .., + ), + .. + }, + .. + }, ..] => ident.name == kw::SelfLower, + _ => false, + } + } + _ => false, + }; + + if !fn_sig.decl.implicit_self.has_implicit_self() + && self_first_arg + { + if let Some(ty) = fn_sig.decl.inputs.get(0) { + arbitrary_rcvr.push(ty.span); + } + return false; + } + } + } // We only want to suggest public or local traits (#45781). item.vis == ty::Visibility::Public || info.def_id.is_local() }) .is_some() }) .collect::>(); + for span in &arbitrary_rcvr { + err.span_label( + *span, + "the method might not be found because of this arbitrary self type", + ); + } if !candidates.is_empty() { // Sort from most relevant to least relevant. @@ -809,7 +1007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let message = |action| { format!( "the following {traits_define} an item `{name}`, perhaps you need to {action} \ - {one_of_them}:", + {one_of_them}:", traits_define = if candidates.len() == 1 { "trait defines" } else { "traits define" }, action = action, @@ -907,19 +1105,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if !suggested { - let mut msg = message(if let Some(param) = param_type { + let action = if let Some(param) = param_type { format!("restrict type parameter `{}` with", param) } else { + // FIXME: it might only need to be imported into scope, not implemented. "implement".to_string() - }); - for (i, trait_info) in candidates.iter().enumerate() { - msg.push_str(&format!( - "\ncandidate #{}: `{}`", - i + 1, - self.tcx.def_path_str(trait_info.def_id), - )); + }; + let mut use_note = true; + if let [trait_info] = &candidates[..] { + if let Some(span) = self.tcx.hir().span_if_local(trait_info.def_id) { + err.span_note( + self.tcx.sess.source_map().def_span(span), + &format!( + "`{}` defines an item `{}`, perhaps you need to {} it", + self.tcx.def_path_str(trait_info.def_id), + item_name, + action + ), + ); + use_note = false + } + } + if use_note { + let mut msg = message(action); + for (i, trait_info) in candidates.iter().enumerate() { + msg.push_str(&format!( + "\ncandidate #{}: `{}`", + i + 1, + self.tcx.def_path_str(trait_info.def_id), + )); + } + err.note(&msg[..]); } - err.note(&msg[..]); } } } @@ -1129,9 +1346,9 @@ impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> { } } - type Map = Map<'tcx>; + type Map = intravisit::ErasedMap<'tcx>; - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { intravisit::NestedVisitorMap::None } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a825856e38a..368f64e4d41 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,22 +87,11 @@ mod upvar; mod wfcheck; pub mod writeback; -use crate::astconv::{AstConv, PathSeg}; +use crate::astconv::{AstConv, GenericArgCountMismatch, PathSeg}; use crate::middle::lang_items; -use crate::namespace::Namespace; use rustc::hir::map::blocks::FnLikeNode; -use rustc::hir::map::Map; -use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; -use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282; -use rustc::infer::opaque_types::OpaqueTypeDecl; -use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc::infer::{self, InferCtxt, InferOk, InferResult}; use rustc::middle::region; use rustc::mir::interpret::ConstValue; -use rustc::session::parse::feature_err; -use rustc::traits::error_reporting::recursive_type_with_infinite_size_error; -use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, }; @@ -115,6 +104,8 @@ use rustc::ty::{ self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType, WithConstness, }; +use rustc_ast::ast; +use rustc_ast::util::parser::ExprPrecedence; use rustc_attr as attr; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -126,13 +117,28 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, QPath}; use rustc_index::vec::Idx; +use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; +use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_infer::infer::{self, InferCtxt, InferOk, InferResult, TyCtxtInferExt}; +use rustc_session::config::{self, EntryFnType}; +use rustc_session::lint; +use rustc_session::parse::feature_err; +use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{self, BytePos, MultiSpan, Span}; use rustc_target::spec::abi::Abi; -use syntax::ast; -use syntax::util::parser::ExprPrecedence; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::opaque_types::{InferCtxtExt as _, OpaqueTypeDecl}; +use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; +use rustc_trait_selection::traits::{ + self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, +}; use std::cell::{Cell, Ref, RefCell, RefMut}; use std::cmp; @@ -142,10 +148,7 @@ use std::mem::replace; use std::ops::{self, Deref}; use std::slice; -use crate::lint; use crate::require_c_abi_if_c_variadic; -use crate::session::config::EntryFnType; -use crate::session::Session; use crate::util::common::{indenter, ErrorReported}; use crate::TypeAndSubsts; @@ -458,7 +461,7 @@ pub enum Diverges { /// where all arms diverge), we may be /// able to provide a more informative /// message to the user. - /// If this is `None`, a default messsage + /// If this is `None`, a default message /// will be generated, which is suitable /// for most cases. custom_note: Option<&'static str>, @@ -635,9 +638,8 @@ pub struct InheritedBuilder<'tcx> { impl Inherited<'_, 'tcx> { pub fn build(tcx: TyCtxt<'tcx>, def_id: DefId) -> InheritedBuilder<'tcx> { - let hir_id_root = if def_id.is_local() { - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - DefId::local(hir_id.owner) + let hir_id_root = if let Some(def_id) = def_id.as_local() { + tcx.hir().local_def_id_to_hir_id(def_id).owner.to_def_id() } else { def_id }; @@ -738,8 +740,8 @@ impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { } pub fn check_wf_new(tcx: TyCtxt<'_>) { - let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); - tcx.hir().krate().par_visit_all_item_likes(&mut visit); + let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); + tcx.hir().krate().par_visit_all_item_likes(&visit); } fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) { @@ -812,14 +814,14 @@ fn primary_body_of( }, Node::TraitItem(item) => match item.kind { hir::TraitItemKind::Const(ref ty, Some(body)) => Some((body, Some(ty), None, None)), - hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => { + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { Some((body, None, Some(&sig.header), Some(&sig.decl))) } _ => None, }, Node::ImplItem(item) => match item.kind { hir::ImplItemKind::Const(ref ty, body) => Some((body, Some(ty), None, None)), - hir::ImplItemKind::Method(ref sig, body) => { + hir::ImplItemKind::Fn(ref sig, body) => { Some((body, None, Some(&sig.header), Some(&sig.decl))) } _ => None, @@ -897,7 +899,7 @@ where ty::Opaque(def_id, substs) => { debug!("fixup_opaque_types: found type {:?}", ty); // Here, we replace any inference variables that occur within - // the substs of an opaque type. By definition, any type occuring + // the substs of an opaque type. By definition, any type occurring // in the substs has a corresponding generic parameter, which is what // we replace it with. // This replacement is only run on the function signature, so any @@ -1125,7 +1127,7 @@ fn typeck_tables_of_with_fallback<'tcx>( // Consistency check our TypeckTables instance can hold all ItemLocalIds // it will need to hold. - assert_eq!(tables.local_id_root, Some(DefId::local(id.owner))); + assert_eq!(tables.local_id_root, Some(id.owner.to_def_id())); tables } @@ -1173,9 +1175,9 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { - type Map = Map<'tcx>; + type Map = intravisit::ErasedMap<'tcx>; - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } @@ -1316,7 +1318,7 @@ fn check_fn<'a, 'tcx>( fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); // Resume type defaults to `()` if the generator has no argument. - let resume_ty = fn_sig.inputs().get(0).map(|ty| *ty).unwrap_or_else(|| tcx.mk_unit()); + let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit()); fcx.resume_yield_tys = Some((resume_ty, yield_ty)); } @@ -1734,7 +1736,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { for item in items.iter() { let item = tcx.hir().trait_item(item.id); - if let hir::TraitItemKind::Method(sig, _) = &item.kind { + if let hir::TraitItemKind::Fn(sig, _) = &item.kind { let abi = sig.header.abi; fn_maybe_err(tcx, item.ident.span, abi); } @@ -1832,18 +1834,17 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: DefId, span: Span) // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. - if let Ok(static_) = tcx.const_eval_poly(id) { - let alloc = if let ty::ConstKind::Value(ConstValue::ByRef { alloc, .. }) = static_.val { - alloc - } else { - bug!("Matching on non-ByRef static") - }; - if alloc.relocations().len() != 0 { - let msg = "statics with a custom `#[link_section]` must be a \ + match tcx.const_eval_poly(id) { + Ok(ConstValue::ByRef { alloc, .. }) => { + if alloc.relocations().len() != 0 { + let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ extra levels of indirection such as references"; - tcx.sess.span_err(span, msg); + tcx.sess.span_err(span, msg); + } } + Ok(_) => bug!("Matching on non-ByRef static"), + Err(_) => {} } } @@ -1893,13 +1894,16 @@ fn check_specialization_validity<'tcx>( ) { let kind = match impl_item.kind { hir::ImplItemKind::Const(..) => ty::AssocKind::Const, - hir::ImplItemKind::Method(..) => ty::AssocKind::Method, + hir::ImplItemKind::Fn(..) => ty::AssocKind::Method, hir::ImplItemKind::OpaqueTy(..) => ty::AssocKind::OpaqueTy, hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type, }; - let mut ancestor_impls = trait_def - .ancestors(tcx, impl_id) + let ancestors = match trait_def.ancestors(tcx, impl_id) { + Ok(ancestors) => ancestors, + Err(_) => return, + }; + let mut ancestor_impls = ancestors .skip(1) .filter_map(|parent| { if parent.is_from_trait() { @@ -1939,7 +1943,7 @@ fn check_specialization_validity<'tcx>( } }); - // If `opt_result` is `None`, we have only encoutered `default impl`s that don't contain the + // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the // item. This is allowed, the item isn't actually getting specialized here. let result = opt_result.unwrap_or(Ok(())); @@ -1966,26 +1970,22 @@ fn check_impl_items_against_trait<'tcx>( // Locate trait definition and items let trait_def = tcx.trait_def(impl_trait_ref.def_id); - let mut overridden_associated_type = None; let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id)); // Check existing impl methods to see if they are both present in trait // and compatible with trait signature for impl_item in impl_items() { + let namespace = impl_item.kind.namespace(); let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id)); let ty_trait_item = tcx .associated_items(impl_trait_ref.def_id) - .iter() - .find(|ac| { - Namespace::from(&impl_item.kind) == Namespace::from(ac.kind) - && tcx.hygienic_eq(ty_impl_item.ident, ac.ident, impl_trait_ref.def_id) - }) + .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id) .or_else(|| { // Not compatible, but needed for the error message tcx.associated_items(impl_trait_ref.def_id) - .iter() - .find(|ac| tcx.hygienic_eq(ty_impl_item.ident, ac.ident, impl_trait_ref.def_id)) + .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id) + .next() }); // Check that impl definition matches trait definition @@ -2020,7 +2020,7 @@ fn check_impl_items_against_trait<'tcx>( err.emit() } } - hir::ImplItemKind::Method(..) => { + hir::ImplItemKind::Fn(..) => { let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); if ty_trait_item.kind == ty::AssocKind::Method { compare_impl_method( @@ -2051,9 +2051,6 @@ fn check_impl_items_against_trait<'tcx>( hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(_) => { let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); if ty_trait_item.kind == ty::AssocKind::Type { - if ty_trait_item.defaultness.has_value() { - overridden_associated_type = Some(impl_item); - } compare_ty_impl( tcx, &ty_impl_item, @@ -2087,20 +2084,17 @@ fn check_impl_items_against_trait<'tcx>( // Check for missing items from trait let mut missing_items = Vec::new(); - let mut invalidated_items = Vec::new(); - let associated_type_overridden = overridden_associated_type.is_some(); - for trait_item in tcx.associated_items(impl_trait_ref.def_id) { - let is_implemented = trait_def - .ancestors(tcx, impl_id) - .leaf_def(tcx, trait_item.ident, trait_item.kind) - .map(|node_item| !node_item.node.is_from_trait()) - .unwrap_or(false); - - if !is_implemented && !traits::impl_is_default(tcx, impl_id) { - if !trait_item.defaultness.has_value() { - missing_items.push(*trait_item); - } else if associated_type_overridden { - invalidated_items.push(trait_item.ident); + if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id) { + for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() { + let is_implemented = ancestors + .leaf_def(tcx, trait_item.ident, trait_item.kind) + .map(|node_item| !node_item.node.is_from_trait()) + .unwrap_or(false); + + if !is_implemented && !traits::impl_is_default(tcx, impl_id) { + if !trait_item.defaultness.has_value() { + missing_items.push(*trait_item); + } } } } @@ -2108,19 +2102,6 @@ fn check_impl_items_against_trait<'tcx>( if !missing_items.is_empty() { missing_items_err(tcx, impl_span, &missing_items, full_impl_span); } - - if !invalidated_items.is_empty() { - let invalidator = overridden_associated_type.unwrap(); - struct_span_err!( - tcx.sess, - invalidator.span, - E0399, - "the following trait items need to be reimplemented as `{}` was overridden: `{}`", - invalidator.ident, - invalidated_items.iter().map(|name| name.to_string()).collect::>().join("`, `") - ) - .emit(); - } } fn missing_items_err( @@ -2926,14 +2907,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("resolve_vars_with_obligations(ty={:?})", ty); // No Infer()? Nothing needs doing. - if !ty.has_infer_types() && !ty.has_infer_consts() { + if !ty.has_infer_types_or_consts() { debug!("resolve_vars_with_obligations: ty={:?}", ty); return ty; } // If `ty` is a type variable, see whether we already know what it is. ty = self.resolve_vars_if_possible(&ty); - if !ty.has_infer_types() && !ty.has_infer_consts() { + if !ty.has_infer_types_or_consts() { debug!("resolve_vars_with_obligations: ty={:?}", ty); return ty; } @@ -3002,7 +2983,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method); - self.write_resolution(hir_id, Ok((DefKind::Method, method.def_id))); + self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); self.write_substs(hir_id, method.substs); // When the method is confirmed, the `method.substs` includes @@ -3478,7 +3459,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // } // ``` // - // In the above snippet, the inference varaible created by + // In the above snippet, the inference variable created by // instantiating `Option` will be completely unconstrained. // We treat this as a non-defining use by making the inference // variable fall back to the opaque type itself. @@ -3844,17 +3825,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error_code: &str, c_variadic: bool, sugg_unit: bool| { + let (span, start_span, args) = match &expr.kind { + hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]), + hir::ExprKind::MethodCall(path_segment, span, args) => ( + *span, + // `sp` doesn't point at the whole `foo.bar()`, only at `bar`. + path_segment + .args + .and_then(|args| args.args.iter().last()) + // Account for `foo.bar::()`. + .map(|arg| { + // Skip the closing `>`. + tcx.sess + .source_map() + .next_point(tcx.sess.source_map().next_point(arg.span())) + }) + .unwrap_or(*span), + &args[1..], // Skip the receiver. + ), + k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k), + }; + let arg_spans = if args.is_empty() { + // foo() + // ^^^-- supplied 0 arguments + // | + // expected 2 arguments + vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())] + } else { + // foo(1, 2, 3) + // ^^^ - - - supplied 3 arguments + // | + // expected 2 arguments + args.iter().map(|arg| arg.span).collect::>() + }; + let mut err = tcx.sess.struct_span_err_with_code( - sp, + span, &format!( "this function takes {}{} but {} {} supplied", if c_variadic { "at least " } else { "" }, - potentially_plural_count(expected_count, "parameter"), - potentially_plural_count(arg_count, "parameter"), + potentially_plural_count(expected_count, "argument"), + potentially_plural_count(arg_count, "argument"), if arg_count == 1 { "was" } else { "were" } ), DiagnosticId::Error(error_code.to_owned()), ); + let label = format!("supplied {}", potentially_plural_count(arg_count, "argument")); + for (i, span) in arg_spans.into_iter().enumerate() { + err.span_label( + span, + if arg_count == 0 || i + 1 == arg_count { &label } else { "" }, + ); + } if let Some(def_s) = def_span.map(|sp| tcx.sess.source_map().def_span(sp)) { err.span_label(def_s, "defined here"); @@ -3871,11 +3893,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } else { err.span_label( - sp, + span, format!( "expected {}{}", if c_variadic { "at least " } else { "" }, - potentially_plural_count(expected_count, "parameter") + potentially_plural_count(expected_count, "argument") ), ); } @@ -4219,7 +4241,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let substs = self.fresh_substs_for_item(span, did); let substd_ty = self.instantiate_type_scheme(span, &substs, &ity); - TypeAndSubsts { substs: substs, ty: substd_ty } + TypeAndSubsts { substs, ty: substd_ty } } /// Unifies the output type with the expected type early, for more coercions @@ -4718,9 +4740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id)); match node { Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) - | Node::ImplItem(&hir::ImplItem { - kind: hir::ImplItemKind::Method(_, body_id), .. - }) => { + | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { let body = self.tcx.hir().body(body_id); if let ExprKind::Block(block, _) = &body.value.kind { return Some(block.span); @@ -4754,12 +4774,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Node::TraitItem(&hir::TraitItem { ident, - kind: hir::TraitItemKind::Method(ref sig, ..), + kind: hir::TraitItemKind::Fn(ref sig, ..), .. }) => Some((&sig.decl, ident, true)), Node::ImplItem(&hir::ImplItem { ident, - kind: hir::ImplItemKind::Method(ref sig, ..), + kind: hir::ImplItemKind::Fn(ref sig, ..), .. }) => Some((&sig.decl, ident, false)), _ => None, @@ -4844,11 +4864,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match hir.get_if_local(def_id) { Some(Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })) | Some(Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Method(_, body_id), + kind: hir::ImplItemKind::Fn(_, body_id), .. })) | Some(Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Method(.., hir::TraitMethod::Provided(body_id)), + kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)), .. })) => { let body = hir.body(*body_id); @@ -4919,7 +4939,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .join(", ") } Some(Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Method(.., hir::TraitMethod::Required(idents)), + kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)), .. })) => { sugg_call = idents @@ -4981,7 +5001,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sugg = if receiver.ends_with(".clone()") && method_call_list.contains(&method_call.as_str()) { - let max_len = receiver.rfind(".").unwrap(); + let max_len = receiver.rfind('.').unwrap(); format!("{}{}", &receiver[..max_len], method_call) } else { if expr.precedence().order() < ExprPrecedence::MethodCall.order() { @@ -5153,7 +5173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Only suggest changing the return type for methods that // haven't set a return type at all (and aren't `fn main()` or an impl). match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) { - (&hir::FunctionRetTy::DefaultReturn(span), true, true, true) => { + (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { err.span_suggestion( span, "try adding a return type", @@ -5162,18 +5182,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); true } - (&hir::FunctionRetTy::DefaultReturn(span), false, true, true) => { + (&hir::FnRetTy::DefaultReturn(span), false, true, true) => { err.span_label(span, "possibly return type missing here?"); true } - (&hir::FunctionRetTy::DefaultReturn(span), _, false, true) => { + (&hir::FnRetTy::DefaultReturn(span), _, false, true) => { // `fn main()` must return `()`, do not suggest changing return type err.span_label(span, "expected `()` because of default return type"); true } // expectation was caused by something else, not the default return - (&hir::FunctionRetTy::DefaultReturn(_), _, _, false) => false, - (&hir::FunctionRetTy::Return(ref ty), _, _, _) => { + (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false, + (&hir::FnRetTy::Return(ref ty), _, _, _) => { // Only point to return type if the expected type is the return type, as if they // are not, the expectation must have been caused by something else. debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind); @@ -5225,7 +5245,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Check for `Future` implementations by constructing a predicate to // prove: `::Output == U` let future_trait = self.tcx.lang_items().future_trait().unwrap(); - let item_def_id = self.tcx.associated_items(future_trait)[0].def_id; + let item_def_id = self + .tcx + .associated_items(future_trait) + .in_definition_order() + .next() + .unwrap() + .def_id; let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate { // `::Output` @@ -5343,7 +5369,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_alias_variant_ctor = true; } } - Res::Def(DefKind::Method, def_id) | Res::Def(DefKind::AssocConst, def_id) => { + Res::Def(DefKind::AssocFn, def_id) | Res::Def(DefKind::AssocConst, def_id) => { let container = tcx.associated_item(def_id).container; debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); match container { @@ -5410,10 +5436,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parameter internally, but we don't allow users to specify the // parameter's value explicitly, so we have to do some error- // checking here. - let suppress_errors = AstConv::check_generic_arg_count_for_call( - tcx, span, &generics, &seg, false, // `is_method_call` - ); - if suppress_errors { + if let Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }) = + AstConv::check_generic_arg_count_for_call( + tcx, span, &generics, &seg, false, // `is_method_call` + ) + { infer_args_for_err.insert(index); self.set_tainted_by_errors(); // See issue #53251. } @@ -5425,9 +5452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or(false); let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { - let ty = self.impl_self_ty(span, impl_def_id).ty; - let adt_def = ty.ty_adt_def(); - + let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id)); match ty.kind { ty::Adt(adt_def, substs) if adt_def.has_ctor() => { let variant = adt_def.non_enum_variant(); @@ -5442,7 +5467,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, "the `Self` constructor can only be used with tuple or unit structs", ); - if let Some(adt_def) = adt_def { + if let Some(adt_def) = ty.ty_adt_def() { match adt_def.adt_kind() { AdtKind::Enum => { err.help("did you mean to use one of the enum's variants?"); @@ -5478,6 +5503,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &[][..], has_self, self_ty, + infer_args_for_err.is_empty(), // Provide the generic args, and whether types should be inferred. |def_id| { if let Some(&PathSeg(_, index)) = @@ -5623,8 +5649,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.sess.span_err( span, - "this function can only be invoked \ - directly, not through a function pointer", + "this function can only be invoked directly, not through a function pointer", ); } @@ -5763,7 +5788,7 @@ fn fatally_break_rust(sess: &Session) { handler.note_without_error(&format!( "rustc {} running on {}", option_env!("CFG_VERSION").unwrap_or("unknown_version"), - crate::session::config::host_triple(), + config::host_triple(), )); } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 028c39b80e4..f589805e1e2 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -2,14 +2,15 @@ use super::method::MethodCallee; use super::{FnCtxt, Needs}; -use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint}; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc_errors::{self, struct_span_err, Applicability}; +use rustc_ast::ast::Ident; +use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_span::Span; -use syntax::ast::Ident; +use rustc_trait_selection::infer::InferCtxtExt; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Checks a `a = b` @@ -25,7 +26,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { - self.enforce_builtin_binop_types(lhs, lhs_ty, rhs, rhs_ty, op); + self.enforce_builtin_binop_types(&lhs.span, lhs_ty, &rhs.span, rhs_ty, op); self.tcx.mk_unit() } else { return_ty @@ -86,8 +87,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) { - let builtin_return_ty = - self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op); + let builtin_return_ty = self.enforce_builtin_binop_types( + &lhs_expr.span, + lhs_ty, + &rhs_expr.span, + rhs_ty, + op, + ); self.demand_suptype(expr.span, builtin_return_ty, return_ty); } @@ -98,19 +104,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn enforce_builtin_binop_types( &self, - lhs_expr: &'tcx hir::Expr<'tcx>, + lhs_span: &Span, lhs_ty: Ty<'tcx>, - rhs_expr: &'tcx hir::Expr<'tcx>, + rhs_span: &Span, rhs_ty: Ty<'tcx>, op: hir::BinOp, ) -> Ty<'tcx> { debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op)); + // Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work. + // (See https://github.com/rust-lang/rust/issues/57447.) + let (lhs_ty, rhs_ty) = (deref_ty_if_possible(lhs_ty), deref_ty_if_possible(rhs_ty)); + let tcx = self.tcx; match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { - self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty); - self.demand_suptype(rhs_expr.span, tcx.mk_bool(), rhs_ty); + self.demand_suptype(*lhs_span, tcx.mk_bool(), lhs_ty); + self.demand_suptype(*rhs_span, tcx.mk_bool(), rhs_ty); tcx.mk_bool() } @@ -121,13 +131,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { BinOpCategory::Math | BinOpCategory::Bitwise => { // both LHS and RHS and result will have the same type - self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty); + self.demand_suptype(*rhs_span, lhs_ty, rhs_ty); lhs_ty } BinOpCategory::Comparison => { // both LHS and RHS and result will have the same type - self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty); + self.demand_suptype(*rhs_span, lhs_ty, rhs_ty); tcx.mk_bool() } } @@ -312,11 +322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, missing_trait )); } else if !suggested_deref { - err.note(&format!( - "an implementation of `{}` might \ - be missing for `{}`", - missing_trait, lhs_ty - )); + suggest_impl_missing(&mut err, lhs_ty, &missing_trait); } } err.emit(); @@ -458,11 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, missing_trait )); } else if !suggested_deref && !involves_fn { - err.note(&format!( - "an implementation of `{}` might \ - be missing for `{}`", - missing_trait, lhs_ty - )); + suggest_impl_missing(&mut err, lhs_ty, &missing_trait); } } err.emit(); @@ -494,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(hir_id) => hir_id, None => return false, }; - if self.tcx.has_typeck_tables(def_id) == false { + if !self.tcx.has_typeck_tables(def_id) { return false; } let fn_sig = { @@ -511,7 +513,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(hir_id) => hir_id, None => return false, }; - if self.tcx.has_typeck_tables(def_id) == false { + if !self.tcx.has_typeck_tables(def_id) { return false; } match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(hir_id) { @@ -528,7 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .lookup_op_method(fn_sig.output(), &[other_ty], Op::Binary(op, is_assign)) .is_ok() { - let (variable_snippet, applicability) = if fn_sig.inputs().len() > 0 { + let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() { ( format!("{}( /* arguments */ )", source_map.span_to_snippet(span).unwrap()), Applicability::HasPlaceholders, @@ -596,15 +598,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(lstring) => { err.span_suggestion( lhs_expr.span, - if lstring.starts_with("&") { + if lstring.starts_with('&') { remove_borrow_msg } else { msg }, - if lstring.starts_with("&") { + if lstring.starts_with('&') { // let a = String::new(); // let _ = &a + "bar"; - format!("{}", &lstring[1..]) + lstring[1..].to_string() } else { format!("{}.to_owned()", lstring) }, @@ -629,10 +631,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_assign, ) { (Ok(l), Ok(r), false) => { - let to_string = if l.starts_with("&") { + let to_string = if l.starts_with('&') { // let a = String::new(); let b = String::new(); // let _ = &a + b; - format!("{}", &l[1..]) + l[1..].to_string() } else { format!("{}.to_owned()", l) }; @@ -698,11 +700,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::UnOp::UnNot => "std::ops::Not", hir::UnOp::UnDeref => "std::ops::UnDerf", }; - err.note(&format!( - "an implementation of `{}` might \ - be missing for `{}`", - missing_trait, operand_ty - )); + suggest_impl_missing(&mut err, operand_ty, &missing_trait); } } err.emit(); @@ -862,6 +860,14 @@ enum Op { Unary(hir::UnOp, Span), } +/// Dereferences a single level of immutable referencing. +fn deref_ty_if_possible(ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.kind { + ty::Ref(_, ty, hir::Mutability::Not) => ty, + _ => ty, + } +} + /// Returns `true` if this is a built-in arithmetic operation (e.g., u32 /// + u32, i16x4 == i16x4) and false if these types would have to be /// overloaded to be legal. There are two reasons that we distinguish @@ -878,7 +884,11 @@ enum Op { /// Reason #2 is the killer. I tried for a while to always use /// overloaded logic and just check the types in constants/codegen after /// the fact, and it worked fine, except for SIMD types. -nmatsakis -fn is_builtin_binop(lhs: Ty<'_>, rhs: Ty<'_>, op: hir::BinOp) -> bool { +fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool { + // Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work. + // (See https://github.com/rust-lang/rust/issues/57447.) + let (lhs, rhs) = (deref_ty_if_possible(lhs), deref_ty_if_possible(rhs)); + match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => true, @@ -908,3 +918,16 @@ fn is_builtin_binop(lhs: Ty<'_>, rhs: Ty<'_>, op: hir::BinOp) -> bool { } } } + +/// If applicable, note that an implementation of `trait` for `ty` may fix the error. +fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_trait: &str) { + if let Adt(def, _) = ty.peel_refs().kind { + if def.did.is_local() { + err.note(&format!( + "an implementation of `{}` might \ + be missing for `{}`", + missing_trait, ty + )); + } + } +} diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 47baae68608..0f3884de84e 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1,19 +1,19 @@ use crate::check::FnCtxt; -use rustc::infer; -use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc::traits::Pattern; use rustc::ty::subst::GenericArg; use rustc::ty::{self, BindingMode, Ty, TypeFoldable}; +use rustc_ast::ast; +use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{HirId, Pat, PatKind}; +use rustc_infer::infer; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_span::hygiene::DesugaringKind; -use rustc_span::Span; -use syntax::ast; -use syntax::util::lev_distance::find_best_match_for_name; +use rustc_span::source_map::{Span, Spanned}; +use rustc_trait_selection::traits::{ObligationCause, Pattern}; use std::cmp; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -63,9 +63,30 @@ struct TopInfo<'tcx> { /// found type `std::result::Result<_, _>` /// ``` span: Option, + /// This refers to the parent pattern. Used to provide extra diagnostic information on errors. + /// ```text + /// error[E0308]: mismatched types + /// --> $DIR/const-in-struct-pat.rs:8:17 + /// | + /// L | struct f; + /// | --------- unit struct defined here + /// ... + /// L | let Thing { f } = t; + /// | ^ + /// | | + /// | expected struct `std::string::String`, found struct `f` + /// | `f` is interpreted as a unit struct, not a new binding + /// | help: bind the struct field to a different name instead: `f: other_f` + /// ``` + parent_pat: Option<&'tcx Pat<'tcx>>, } impl<'tcx> FnCtxt<'_, 'tcx> { + fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> { + let code = Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr }; + self.cause(cause_span, code) + } + fn demand_eqtype_pat_diag( &self, cause_span: Span, @@ -73,9 +94,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { actual: Ty<'tcx>, ti: TopInfo<'tcx>, ) -> Option> { - let code = Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr }; - let cause = self.cause(cause_span, code); - self.demand_eqtype_with_origin(&cause, expected, actual) + self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual) } fn demand_eqtype_pat( @@ -89,6 +108,18 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } } +const INITIAL_BM: BindingMode = BindingMode::BindByValue(hir::Mutability::Not); + +/// Mode for adjusting the expected type and binding mode. +enum AdjustMode { + /// Peel off all immediate reference types. + Peel, + /// Reset binding mode to the initial mode. + Reset, + /// Pass on the input binding mode and expected type. + Pass, +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type check the given top level pattern against the `expected` type. /// @@ -105,8 +136,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Option, origin_expr: bool, ) { - let def_bm = BindingMode::BindByValue(hir::Mutability::Not); - self.check_pat(pat, expected, def_bm, TopInfo { expected, origin_expr, span }); + let info = TopInfo { expected, origin_expr, span, parent_pat: None }; + self.check_pat(pat, expected, INITIAL_BM, info); } /// Type check the given `pat` against the `expected` type @@ -123,12 +154,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm); - let path_resolution = match &pat.kind { + let path_res = match &pat.kind { PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)), _ => None, }; - let is_nrp = self.is_non_ref_pat(pat, path_resolution.map(|(res, ..)| res)); - let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, is_nrp); + let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); + let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); let ty = match pat.kind { PatKind::Wild => expected, @@ -141,14 +172,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti) } PatKind::Path(ref qpath) => { - self.check_pat_path(pat, path_resolution.unwrap(), qpath, expected) + self.check_pat_path(pat, path_res.unwrap(), qpath, expected, ti) } PatKind::Struct(ref qpath, fields, etc) => { self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti) } PatKind::Or(pats) => { + let parent_pat = Some(pat); for pat in pats { - self.check_pat(pat, expected, def_bm, ti); + self.check_pat(pat, expected, def_bm, TopInfo { parent_pat, ..ti }); } expected } @@ -223,64 +255,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_bm: BindingMode, - is_non_ref_pat: bool, + adjust_mode: AdjustMode, ) -> (Ty<'tcx>, BindingMode) { - if is_non_ref_pat { - debug!("pattern is non reference pattern"); - self.peel_off_references(pat, expected, def_bm) - } else { - // When you encounter a `&pat` pattern, reset to "by - // value". This is so that `x` and `y` here are by value, - // as they appear to be: - // - // ``` - // match &(&22, &44) { - // (&x, &y) => ... - // } - // ``` - // - // See issue #46688. - let def_bm = match pat.kind { - PatKind::Ref(..) => ty::BindByValue(hir::Mutability::Not), - _ => def_bm, - }; - (expected, def_bm) + match adjust_mode { + AdjustMode::Pass => (expected, def_bm), + AdjustMode::Reset => (expected, INITIAL_BM), + AdjustMode::Peel => self.peel_off_references(pat, expected, def_bm), } } - /// Is the pattern a "non reference pattern"? + /// How should the binding mode and expected type be adjusted? + /// /// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`. - fn is_non_ref_pat(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option) -> bool { - match pat.kind { + fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option) -> AdjustMode { + match &pat.kind { + // Type checking these product-like types successfully always require + // that the expected type be of those types and not reference types. PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Tuple(..) | PatKind::Box(_) | PatKind::Range(..) - | PatKind::Slice(..) => true, - PatKind::Lit(ref lt) => { - let ty = self.check_expr(lt); - match ty.kind { - ty::Ref(..) => false, - _ => true, - } - } + | PatKind::Slice(..) => AdjustMode::Peel, + // String and byte-string literals result in types `&str` and `&[u8]` respectively. + // All other literals result in non-reference types. + // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`. + PatKind::Lit(lt) => match self.check_expr(lt).kind { + ty::Ref(..) => AdjustMode::Pass, + _ => AdjustMode::Peel, + }, PatKind::Path(_) => match opt_path_res.unwrap() { - Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => false, - _ => true, + // These constants can be of a reference type, e.g. `const X: &u8 = &0;`. + // Peeling the reference types too early will cause type checking failures. + // Although it would be possible to *also* peel the types of the constants too. + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => AdjustMode::Pass, + // In the `ValueNS`, we have `SelfCtor(..) | Ctor(_, Const), _)` remaining which + // could successfully compile. The former being `Self` requires a unit struct. + // In either case, and unlike constants, the pattern itself cannot be + // a reference type wherefore peeling doesn't give up any expressivity. + _ => AdjustMode::Peel, }, - // FIXME(or_patterns; Centril | dlrobertson): To keep things compiling - // for or-patterns at the top level, we need to make `p_0 | ... | p_n` - // a "non reference pattern". For example the following currently compiles: + // When encountering a `& mut? pat` pattern, reset to "by value". + // This is so that `x` and `y` here are by value, as they appear to be: + // // ``` - // match &1 { - // e @ &(1...2) | e @ &(3...4) => {} - // _ => {} + // match &(&22, &44) { + // (&x, &y) => ... // } // ``` // - // We should consider whether we should do something special in nested or-patterns. - PatKind::Or(_) | PatKind::Wild | PatKind::Binding(..) | PatKind::Ref(..) => false, + // See issue #46688. + PatKind::Ref(..) => AdjustMode::Reset, + // A `_` pattern works with any expected type, so there's no need to do anything. + PatKind::Wild + // Bindings also work with whatever the expected type is, + // and moreover if we peel references off, that will give us the wrong binding type. + // Also, we can have a subpattern `binding @ pat`. + // Each side of the `@` should be treated independently (like with OR-patterns). + | PatKind::Binding(..) + // An OR-pattern just propagates to each individual alternative. + // This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`. + // In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`. + | PatKind::Or(_) => AdjustMode::Pass, } } @@ -324,7 +360,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); } - if pat_adjustments.len() > 0 { + if !pat_adjustments.is_empty() { debug!("default binding mode is now {:?}", def_bm); self.inh.tables.borrow_mut().pat_adjustments_mut().insert(pat.hir_id, pat_adjustments); } @@ -346,16 +382,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Byte string patterns behave the same way as array patterns // They can denote both statically and dynamically-sized byte arrays. let mut pat_ty = ty; - if let hir::ExprKind::Lit(ref lt) = lt.kind { - if let ast::LitKind::ByteStr(_) = lt.node { - let expected_ty = self.structurally_resolved_type(span, expected); - if let ty::Ref(_, r_ty, _) = expected_ty.kind { - if let ty::Slice(_) = r_ty.kind { - let tcx = self.tcx; - pat_ty = - tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8)); - } - } + if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(_), .. }) = lt.kind { + let expected = self.structurally_resolved_type(span, expected); + if let ty::Ref(_, ty::TyS { kind: ty::Slice(_), .. }, _) = expected.kind { + let tcx = self.tcx; + pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8)); } } @@ -369,7 +400,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // &'static str <: expected // // then that's equivalent to there existing a LUB. - if let Some(mut err) = self.demand_suptype_diag(span, expected, pat_ty) { + let cause = self.pattern_cause(ti, span); + if let Some(mut err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { err.emit_unless( ti.span .filter(|&s| { @@ -487,7 +519,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_ident( &self, - pat: &Pat<'_>, + pat: &'tcx Pat<'tcx>, ba: hir::BindingAnnotation, var_id: HirId, sub: Option<&'tcx Pat<'tcx>>, @@ -508,7 +540,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let local_ty = self.local_ty(pat.span, pat.hir_id).decl_ty; let eq_ty = match bm { ty::BindByReference(mutbl) => { - // If the binding is like `ref x | ref const x | ref mut x` + // If the binding is like `ref x | ref mut x`, // then `x` is assigned a value of type `&M T` where M is the // mutability and T is the expected type. // @@ -528,17 +560,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be. if var_id != pat.hir_id { - let vt = self.local_ty(pat.span, var_id).decl_ty; - self.demand_eqtype_pat(pat.span, vt, local_ty, ti); + self.check_binding_alt_eq_ty(pat.span, var_id, local_ty, ti); } if let Some(p) = sub { - self.check_pat(&p, expected, def_bm, ti); + self.check_pat(&p, expected, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); } local_ty } + fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx>) { + let var_ty = self.local_ty(span, var_id).decl_ty; + if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { + let hir = self.tcx.hir(); + let var_ty = self.resolve_vars_with_obligations(var_ty); + let msg = format!("first introduced with type `{}` here", var_ty); + err.span_label(hir.span(var_id), msg); + let in_match = hir.parent_iter(var_id).any(|(_, n)| { + matches!( + n, + hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Match(.., hir::MatchSource::Normal), + .. + }) + ) + }); + let pre = if in_match { "in the same arm, " } else { "" }; + err.note(&format!("{}a binding must have the same type in all alternatives", pre)); + err.emit(); + } + } + fn borrow_pat_suggestion( &self, err: &mut DiagnosticBuilder<'_>, @@ -620,6 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant_ty } else { for field in fields { + let ti = TopInfo { parent_pat: Some(&pat), ..ti }; self.check_pat(&field.pat, self.tcx.types.err, def_bm, ti); } return self.tcx.types.err; @@ -629,9 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype_pat(pat.span, expected, pat_ty, ti); // Type-check subpatterns. - if self - .check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm, ti) - { + if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, etc, def_bm, ti) { pat_ty } else { self.tcx.types.err @@ -644,6 +696,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { path_resolution: (Res, Option>, &'b [hir::PathSegment<'b>]), qpath: &hir::QPath<'_>, expected: Ty<'tcx>, + ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; @@ -654,7 +707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.set_tainted_by_errors(); return tcx.types.err; } - Res::Def(DefKind::Method, _) + Res::Def(DefKind::AssocFn, _) | Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => { report_unexpected_variant_res(tcx, res, pat.span, qpath); @@ -663,19 +716,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..) | Res::Def(DefKind::Const, _) - | Res::Def(DefKind::AssocConst, _) => {} // OK + | Res::Def(DefKind::AssocConst, _) + | Res::Def(DefKind::ConstParam, _) => {} // OK _ => bug!("unexpected pattern resolution: {:?}", res), } // Type-check the path. - let pat_ty = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id).0; - self.demand_suptype(pat.span, expected, pat_ty); + let (pat_ty, pat_res) = + self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id); + if let Some(err) = + self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty) + { + self.emit_bad_pat_path(err, pat.span, res, pat_res, segments, ti.parent_pat); + } pat_ty } + fn emit_bad_pat_path( + &self, + mut e: DiagnosticBuilder<'_>, + pat_span: Span, + res: Res, + pat_res: Res, + segments: &'b [hir::PathSegment<'b>], + parent_pat: Option<&Pat<'_>>, + ) { + if let Some(span) = self.tcx.hir().res_span(pat_res) { + e.span_label(span, &format!("{} defined here", res.descr())); + if let [hir::PathSegment { ident, .. }] = &*segments { + e.span_label( + pat_span, + &format!( + "`{}` is interpreted as {} {}, not a new binding", + ident, + res.article(), + res.descr(), + ), + ); + let (msg, sugg) = match parent_pat { + Some(Pat { kind: hir::PatKind::Struct(..), .. }) => ( + "bind the struct field to a different name instead", + format!("{}: other_{}", ident, ident.as_str().to_lowercase()), + ), + _ => ( + "introduce a new binding instead", + format!("other_{}", ident.as_str().to_lowercase()), + ), + }; + e.span_suggestion(ident.span, msg, sugg, Applicability::HasPlaceholders); + } + } + e.emit(); + } + fn check_pat_tuple_struct( &self, - pat: &Pat<'_>, + pat: &'tcx Pat<'tcx>, qpath: &hir::QPath<'_>, subpats: &'tcx [&'tcx Pat<'tcx>], ddpos: Option, @@ -685,8 +781,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let tcx = self.tcx; let on_error = || { + let parent_pat = Some(pat); for pat in subpats { - self.check_pat(&pat, tcx.types.err, def_bm, ti); + self.check_pat(&pat, tcx.types.err, def_bm, TopInfo { parent_pat, ..ti }); } }; let report_unexpected_res = |res: Res| { @@ -697,7 +794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg); match (res, &pat.kind) { - (Res::Def(DefKind::Fn, _), _) | (Res::Def(DefKind::Method, _), _) => { + (Res::Def(DefKind::Fn, _), _) | (Res::Def(DefKind::AssocFn, _), _) => { err.span_label(pat.span, "`fn` calls are not allowed in patterns"); err.help( "for more information, visit \ @@ -734,7 +831,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { on_error(); return tcx.types.err; } - Res::Def(DefKind::AssocConst, _) | Res::Def(DefKind::Method, _) => { + Res::Def(DefKind::AssocConst, _) | Res::Def(DefKind::AssocFn, _) => { report_unexpected_res(res); return tcx.types.err; } @@ -761,7 +858,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); - self.check_pat(&subpat, field_ty, def_bm, ti); + self.check_pat(&subpat, field_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); self.tcx.check_stability(variant.fields[i].did, Some(pat.hir_id), subpat.span); } @@ -809,7 +906,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`. let missing_parenthesis = match (&expected.kind, fields, had_err) { - // #67037: only do this if we could sucessfully type-check the expected type against + // #67037: only do this if we could successfully type-check the expected type against // the tuple struct pattern. Otherwise the substs could get out of range on e.g., // `let P() = U;` where `P != U` with `struct P(T);`. (ty::Adt(_, substs), [field], false) => { @@ -886,7 +983,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let element_tys = tcx.mk_substs(element_tys_iter); let pat_ty = tcx.mk_ty(ty::Tuple(element_tys)); - if let Some(mut err) = self.demand_eqtype_diag(span, expected, pat_ty) { + if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) { err.emit(); // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 @@ -906,8 +1003,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_struct_pat_fields( &self, adt_ty: Ty<'tcx>, - pat_id: HirId, - span: Span, + pat: &'tcx Pat<'tcx>, variant: &'tcx ty::VariantDef, fields: &'tcx [hir::FieldPat<'tcx>], etc: bool, @@ -918,7 +1014,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (substs, adt) = match adt_ty.kind { ty::Adt(adt, substs) => (substs, adt), - _ => span_bug!(span, "struct pattern is not an ADT"), + _ => span_bug!(pat.span, "struct pattern is not an ADT"), }; let kind_name = adt.variant_descr(); @@ -927,7 +1023,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .fields .iter() .enumerate() - .map(|(i, field)| (field.ident.modern(), (i, field))) + .map(|(i, field)| (field.ident.normalize_to_macros_2_0(), (i, field))) .collect::>(); // Keep track of which fields have already appeared in the pattern. @@ -951,7 +1047,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .get(&ident) .map(|(i, f)| { self.write_field_index(field.hir_id, *i); - self.tcx.check_stability(f.did, Some(pat_id), span); + self.tcx.check_stability(f.did, Some(pat.hir_id), span); self.field_ty(span, f, substs) }) .unwrap_or_else(|| { @@ -962,17 +1058,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - self.check_pat(&field.pat, field_ty, def_bm, ti); + self.check_pat(&field.pat, field_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); } let mut unmentioned_fields = variant .fields .iter() - .map(|field| field.ident.modern()) + .map(|field| field.ident.normalize_to_macros_2_0()) .filter(|ident| !used_fields.contains_key(&ident)) .collect::>(); - if inexistent_fields.len() > 0 && !variant.recovered { + if !inexistent_fields.is_empty() && !variant.recovered { self.error_inexistent_fields( kind_name, &inexistent_fields, @@ -985,7 +1081,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc { struct_span_err!( tcx.sess, - span, + pat.span, E0638, "`..` required with {} marked as non-exhaustive", kind_name @@ -997,14 +1093,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if kind_name == "union" { if fields.len() != 1 { tcx.sess - .struct_span_err(span, "union patterns should have exactly one field") + .struct_span_err(pat.span, "union patterns should have exactly one field") .emit(); } if etc { - tcx.sess.struct_span_err(span, "`..` cannot be used in union patterns").emit(); + tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } - } else if !etc && unmentioned_fields.len() > 0 { - self.error_unmentioned_fields(span, &unmentioned_fields, variant); + } else if !etc && !unmentioned_fields.is_empty() { + self.error_unmentioned_fields(pat.span, &unmentioned_fields, variant); } no_field_errors } @@ -1164,7 +1260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_ref( &self, - pat: &Pat<'_>, + pat: &'tcx Pat<'tcx>, inner: &'tcx Pat<'tcx>, mutbl: hir::Mutability, expected: Ty<'tcx>, @@ -1190,7 +1286,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let rptr_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); debug!("check_pat_ref: demanding {:?} = {:?}", expected, rptr_ty); - let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty); + let err = self.demand_eqtype_pat_diag(pat.span, expected, rptr_ty, ti); // Look for a case like `fn foo(&foo: u32)` and suggest // `fn foo(foo: &u32)` @@ -1204,7 +1300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { (tcx.types.err, tcx.types.err) }; - self.check_pat(&inner, inner_ty, def_bm, ti); + self.check_pat(&inner, inner_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); rptr_ty } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index af2ccb45176..57a89614eb1 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -76,9 +76,6 @@ use crate::check::dropck; use crate::check::FnCtxt; use crate::mem_categorization as mc; use crate::middle::region; -use rustc::hir::map::Map; -use rustc::infer::outlives::env::OutlivesEnvironment; -use rustc::infer::{self, RegionObligation, SuppressRegionErrors}; use rustc::ty::adjustment; use rustc::ty::subst::{GenericArgKind, SubstsRef}; use rustc::ty::{self, Ty}; @@ -86,7 +83,11 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::PatKind; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::{self, RegionObligation, RegionckMode}; use rustc_span::Span; +use rustc_trait_selection::infer::OutlivesEnvironmentExt; +use rustc_trait_selection::opaque_types::InferCtxtExt; use std::mem; use std::ops::Deref; @@ -122,10 +123,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcx.visit_body(body); rcx.visit_region_obligations(id); } - rcx.resolve_regions_and_report_errors(SuppressRegionErrors::when_nll_is_enabled(self.tcx)); - - assert!(self.tables.borrow().free_region_map.is_empty()); - self.tables.borrow_mut().free_region_map = rcx.outlives_environment.into_free_region_map(); + rcx.resolve_regions_and_report_errors(RegionckMode::for_item_body(self.tcx)); } /// Region checking during the WF phase for items. `wf_tys` are the @@ -143,7 +141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcx.outlives_environment.add_implied_bounds(self, wf_tys, item_id, span); rcx.outlives_environment.save_implied_bounds(item_id); rcx.visit_region_obligations(item_id); - rcx.resolve_regions_and_report_errors(SuppressRegionErrors::default()); + rcx.resolve_regions_and_report_errors(RegionckMode::default()); } /// Region check a function body. Not invoked on closures, but @@ -166,13 +164,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcx.visit_fn_body(fn_id, body, self.tcx.hir().span(fn_id)); } - rcx.resolve_regions_and_report_errors(SuppressRegionErrors::when_nll_is_enabled(self.tcx)); - - // In this mode, we also copy the free-region-map into the - // tables of the enclosing fcx. In the other regionck modes - // (e.g., `regionck_item`), we don't have an enclosing tables. - assert!(self.tables.borrow().free_region_map.is_empty()); - self.tables.borrow_mut().free_region_map = rcx.outlives_environment.into_free_region_map(); + rcx.resolve_regions_and_report_errors(RegionckMode::for_item_body(self.tcx)); } } @@ -353,7 +345,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.select_all_obligations_or_error(); } - fn resolve_regions_and_report_errors(&self, suppress: SuppressRegionErrors) { + fn resolve_regions_and_report_errors(&self, mode: RegionckMode) { self.infcx.process_registered_region_obligations( self.outlives_environment.region_bound_pairs_map(), self.implicit_region_bound, @@ -364,7 +356,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.subject_def_id, &self.region_scope_tree, &self.outlives_environment, - suppress, + mode, ); } @@ -415,9 +407,9 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { // hierarchy, and in particular the relationships between free // regions, until regionck, as described in #3238. - type Map = Map<'tcx>; + type Map = intravisit::ErasedMap<'tcx>; - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index e4502bf134d..1b5f151870c 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -35,16 +35,15 @@ use super::FnCtxt; use crate::expr_use_visitor as euv; use crate::mem_categorization as mc; use crate::mem_categorization::PlaceBase; -use rustc::hir::map::Map; -use rustc::infer::UpvarRegion; use rustc::ty::{self, Ty, TyCtxt, UpvarSubsts}; +use rustc_ast::ast; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_infer::infer::UpvarRegion; use rustc_span::Span; -use syntax::ast; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) { @@ -60,9 +59,9 @@ struct InferBorrowKindVisitor<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { - type Map = Map<'tcx>; + type Map = intravisit::ErasedMap<'tcx>; - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } @@ -119,7 +118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (&var_hir_id, _) in upvars.iter() { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: LocalDefId::from_def_id(closure_def_id), + closure_expr_id: closure_def_id.expect_local(), }; debug!("seed upvar_id {:?}", upvar_id); // Adding the upvar Id to the list of Upvars, which will be added @@ -229,7 +228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let upvar_ty = self.node_ty(var_hir_id); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: LocalDefId::from_def_id(closure_def_id), + closure_expr_id: closure_def_id.expect_local(), }; let capture = self.tables.borrow().upvar_capture(upvar_id); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index fc194e3af97..3255d7b435c 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -1,24 +1,25 @@ use crate::check::{FnCtxt, Inherited}; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; -use rustc::infer::opaque_types::may_define_opaque_type; use rustc::middle::lang_items; -use rustc::session::parse::feature_err; -use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::subst::{InternalSubsts, Subst}; +use rustc::ty::trait_def::TraitSpecializationKind; use rustc::ty::{ self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; +use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; +use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::itemlikevisit::ParItemLikeVisitor; use rustc_hir::ItemKind; +use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::Span; -use syntax::ast; - -use rustc_hir as hir; -use rustc_hir::itemlikevisit::ParItemLikeVisitor; +use rustc_trait_selection::opaque_types::may_define_opaque_type; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; /// Helper type of a temporary returned by `.for_item(...)`. /// This is necessary because we can't write the following bound: @@ -173,7 +174,7 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: DefId) { let trait_item = tcx.hir().expect_trait_item(hir_id); let method_sig = match trait_item.kind { - hir::TraitItemKind::Method(ref sig, _) => Some(sig), + hir::TraitItemKind::Fn(ref sig, _) => Some(sig), _ => None, }; check_object_unsafe_self_trait_by_name(tcx, &trait_item); @@ -207,14 +208,14 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem { trait_should_be_self.push(ty.span) } - hir::TraitItemKind::Method(sig, _) => { + hir::TraitItemKind::Fn(sig, _) => { for ty in sig.decl.inputs { if could_be_self(trait_def_id, ty) { trait_should_be_self.push(ty.span); } } match sig.decl.output { - hir::FunctionRetTy::Return(ty) if could_be_self(trait_def_id, ty) => { + hir::FnRetTy::Return(ty) if could_be_self(trait_def_id, ty) => { trait_should_be_self.push(ty.span); } _ => {} @@ -223,7 +224,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem _ => {} } if !trait_should_be_self.is_empty() { - if rustc::traits::object_safety_violations(tcx, trait_def_id).is_empty() { + if tcx.object_safety_violations(trait_def_id).is_empty() { return; } let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect(); @@ -247,7 +248,7 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) { let impl_item = tcx.hir().expect_impl_item(hir_id); let method_sig = match impl_item.kind { - hir::ImplItemKind::Method(ref sig, _) => Some(sig), + hir::ImplItemKind::Fn(ref sig, _) => Some(sig), _ => None, }; @@ -411,7 +412,9 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { let trait_def_id = tcx.hir().local_def_id(item.hir_id); let trait_def = tcx.trait_def(trait_def_id); - if trait_def.is_marker { + if trait_def.is_marker + || matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker) + { for associated_def_id in &*tcx.associated_item_def_ids(trait_def_id) { struct_span_err!( tcx.sess, @@ -425,10 +428,109 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { for_item(tcx, item).with_fcx(|fcx, _| { check_where_clauses(tcx, fcx, item.span, trait_def_id, None); + check_associated_type_defaults(fcx, trait_def_id); + vec![] }); } +/// Checks all associated type defaults of trait `trait_def_id`. +/// +/// Assuming the defaults are used, check that all predicates (bounds on the +/// assoc type and where clauses on the trait) hold. +fn check_associated_type_defaults(fcx: &FnCtxt<'_, '_>, trait_def_id: DefId) { + let tcx = fcx.tcx; + let substs = InternalSubsts::identity_for_item(tcx, trait_def_id); + + // For all assoc. types with defaults, build a map from + // `>::Assoc` to the default type. + let map = tcx + .associated_items(trait_def_id) + .in_definition_order() + .filter_map(|item| { + if item.kind == ty::AssocKind::Type && item.defaultness.has_value() { + // `>::Assoc` + let proj = ty::ProjectionTy { substs, item_def_id: item.def_id }; + let default_ty = tcx.type_of(item.def_id); + debug!("assoc. type default mapping: {} -> {}", proj, default_ty); + Some((proj, default_ty)) + } else { + None + } + }) + .collect::>(); + + /// Replaces projections of associated types with their default types. + /// + /// This does a "shallow substitution", meaning that defaults that refer to + /// other defaulted assoc. types will still refer to the projection + /// afterwards, not to the other default. For example: + /// + /// ```compile_fail + /// trait Tr { + /// type A: Clone = Vec; + /// type B = u8; + /// } + /// ``` + /// + /// This will end up replacing the bound `Self::A: Clone` with + /// `Vec: Clone`, not with `Vec: Clone`. If we did a deep + /// substitution and ended up with the latter, the trait would be accepted. + /// If an `impl` then replaced `B` with something that isn't `Clone`, + /// suddenly the default for `A` is no longer valid. The shallow + /// substitution forces the trait to add a `B: Clone` bound to be accepted, + /// which means that an `impl` can replace any default without breaking + /// others. + /// + /// Note that this isn't needed for soundness: The defaults would still be + /// checked in any impl that doesn't override them. + struct DefaultNormalizer<'tcx> { + tcx: TyCtxt<'tcx>, + map: FxHashMap, Ty<'tcx>>, + } + + impl<'tcx> ty::fold::TypeFolder<'tcx> for DefaultNormalizer<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.kind { + ty::Projection(proj_ty) => { + if let Some(default) = self.map.get(&proj_ty) { + default + } else { + t.super_fold_with(self) + } + } + _ => t.super_fold_with(self), + } + } + } + + // Now take all predicates defined on the trait, replace any mention of + // the assoc. types with their default, and prove them. + // We only consider predicates that directly mention the assoc. type. + let mut norm = DefaultNormalizer { tcx, map }; + let predicates = fcx.tcx.predicates_of(trait_def_id); + for &(orig_pred, span) in predicates.predicates.iter() { + let pred = orig_pred.fold_with(&mut norm); + if pred != orig_pred { + // Mentions one of the defaulted assoc. types + debug!("default suitability check: proving predicate: {} -> {}", orig_pred, pred); + let pred = fcx.normalize_associated_types_in(span, &pred); + let cause = traits::ObligationCause::new( + span, + fcx.body_id, + traits::ItemObligation(trait_def_id), + ); + let obligation = traits::Obligation::new(cause, fcx.param_env, pred); + + fcx.register_predicate(obligation); + } + } +} + fn check_item_fn(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { for_item(tcx, item).with_fcx(|fcx, tcx| { let def_id = fcx.tcx.hir().local_def_id(item.hir_id); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index b4798fb67f8..fd92284effb 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -4,18 +4,18 @@ use crate::check::FnCtxt; -use rustc::hir::map::Map; -use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282; -use rustc::infer::InferCtxt; use rustc::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc::ty::fold::{TypeFoldable, TypeFolder}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIdSet, DefIndex}; +use rustc_hir::def_id::DefIdSet; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::InferCtxt; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_trait_selection::opaque_types::InferCtxtExt; use std::mem; @@ -61,7 +61,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_fru_field_types(); wbcx.visit_opaque_types(body.value.span); wbcx.visit_coercion_casts(); - wbcx.visit_free_region_map(); wbcx.visit_user_provided_tys(); wbcx.visit_user_provided_sigs(); wbcx.visit_generator_interior_types(); @@ -108,11 +107,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { body: &'tcx hir::Body<'tcx>, rustc_dump_user_substs: bool, ) -> WritebackCx<'cx, 'tcx> { - let owner = body.id().hir_id; + let owner = body.id().hir_id.owner; WritebackCx { fcx, - tables: ty::TypeckTables::empty(Some(DefId::local(owner.owner))), + tables: ty::TypeckTables::empty(Some(owner.to_def_id())), body, rustc_dump_user_substs, } @@ -124,7 +123,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn write_ty_to_tables(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) { debug!("write_ty_to_tables({:?}, {:?})", hir_id, ty); - assert!(!ty.needs_infer() && !ty.has_placeholders()); + assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions()); self.tables.node_types_mut().insert(hir_id, ty); } @@ -243,9 +242,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // traffic in node-ids or update tables in the type context etc. impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { - type Map = Map<'tcx>; + type Map = intravisit::ErasedMap<'tcx>; - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } @@ -326,9 +325,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let new_upvar_capture = match *upvar_capture { ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, ty::UpvarCapture::ByRef(ref upvar_borrow) => { - let r = upvar_borrow.region; - let r = self.resolve(&r, &upvar_id.var_path.hir_id); - ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: upvar_borrow.kind, region: r }) + ty::UpvarCapture::ByRef(ty::UpvarBorrow { + kind: upvar_borrow.kind, + region: self.tcx().lifetimes.re_erased, + }) } }; debug!("Upvar capture for {:?} resolved to {:?}", upvar_id, new_upvar_capture); @@ -342,7 +342,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let common_local_id_root = fcx_tables.local_id_root.unwrap(); for (&id, &origin) in fcx_tables.closure_kind_origins().iter() { - let hir_id = hir::HirId { owner: common_local_id_root.index, local_id: id }; + let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id: id }; self.tables.closure_kind_origins_mut().insert(hir_id, origin); } } @@ -357,11 +357,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - fn visit_free_region_map(&mut self) { - self.tables.free_region_map = self.fcx.tables.borrow().free_region_map.clone(); - debug_assert!(!self.tables.free_region_map.elements().any(|r| r.has_local_value())); - } - fn visit_user_provided_tys(&mut self) { let fcx_tables = self.fcx.tables.borrow(); debug_assert_eq!(fcx_tables.local_id_root, self.tables.local_id_root); @@ -369,7 +364,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let mut errors_buffer = Vec::new(); for (&local_id, c_ty) in fcx_tables.user_provided_types().iter() { - let hir_id = hir::HirId { owner: common_local_id_root.index, local_id }; + let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id }; if cfg!(debug_assertions) && c_ty.has_local_value() { span_bug!(hir_id.to_span(self.fcx.tcx), "writeback: `{:?}` is a local value", c_ty); @@ -444,7 +439,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // figures out the concrete type with `U`, but the stored type is with `T`. let definition_ty = self.fcx.infer_opaque_definition_from_instantiation( def_id, - opaque_defn, + opaque_defn.substs, instantiated_ty, span, ); @@ -562,7 +557,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let common_local_id_root = fcx_tables.local_id_root.unwrap(); for (&local_id, fn_sig) in fcx_tables.liberated_fn_sigs().iter() { - let hir_id = hir::HirId { owner: common_local_id_root.index, local_id }; + let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id }; let fn_sig = self.resolve(fn_sig, &hir_id); self.tables.liberated_fn_sigs_mut().insert(hir_id, fn_sig.clone()); } @@ -574,7 +569,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let common_local_id_root = fcx_tables.local_id_root.unwrap(); for (&local_id, ftys) in fcx_tables.fru_field_types().iter() { - let hir_id = hir::HirId { owner: common_local_id_root.index, local_id }; + let hir_id = hir::HirId { owner: common_local_id_root.expect_local(), local_id }; let ftys = self.resolve(ftys, &hir_id); self.tables.fru_field_types_mut().insert(hir_id, ftys); } @@ -602,23 +597,14 @@ impl Locatable for Span { } } -impl Locatable for DefIndex { - fn to_span(&self, tcx: TyCtxt<'_>) -> Span { - let hir_id = tcx.hir().def_index_to_hir_id(*self); - tcx.hir().span(hir_id) - } -} - impl Locatable for hir::HirId { fn to_span(&self, tcx: TyCtxt<'_>) -> Span { tcx.hir().span(*self) } } -/////////////////////////////////////////////////////////////////////////// -// The Resolver. This is the type folding engine that detects -// unresolved types and so forth. - +/// The Resolver. This is the type folding engine that detects +/// unresolved types and so forth. struct Resolver<'cx, 'tcx> { tcx: TyCtxt<'tcx>, infcx: &'cx InferCtxt<'cx, 'tcx>, @@ -651,7 +637,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match self.infcx.fully_resolve(&t) { - Ok(t) => t, + Ok(t) => self.infcx.tcx.erase_regions(&t), Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); self.report_error(t); @@ -660,15 +646,14 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { } } - // FIXME This should be carefully checked - // We could use `self.report_error` but it doesn't accept a ty::Region, right now. fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - self.infcx.fully_resolve(&r).unwrap_or(self.tcx.lifetimes.re_static) + debug_assert!(!r.is_late_bound(), "Should not be resolving bound region."); + self.tcx.lifetimes.re_erased } fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { match self.infcx.fully_resolve(&ct) { - Ok(ct) => ct, + Ok(ct) => self.infcx.tcx.erase_regions(&ct), Err(_) => { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); // FIXME: we'd like to use `self.report_error`, but it doesn't yet diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index dd833d9751c..d0414af5b21 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -1,13 +1,13 @@ -use crate::lint; use rustc::ty::TyCtxt; +use rustc_ast::ast; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::print::visibility_qualified; +use rustc_session::lint; use rustc_span::Span; -use syntax::ast; pub fn check_crate(tcx: TyCtxt<'_>) { let mut used_trait_imports = DefIdSet::default(); diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 1970b1e5c5d..e24d9bebf65 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -1,14 +1,8 @@ //! Check properties that are required by built-in traits and set //! up data structures required by type-checking/codegen. -use rustc::infer; -use rustc::infer::outlives::env::OutlivesEnvironment; -use rustc::infer::SuppressRegionErrors; use rustc::middle::lang_items::UnsizeTraitLangItem; use rustc::middle::region; -use rustc::traits::misc::{can_type_implement_copy, CopyImplementationError}; -use rustc::traits::predicate_for_trait_def; -use rustc::traits::{self, ObligationCause, TraitEngine}; use rustc::ty::adjustment::CoerceUnsizedInfo; use rustc::ty::TypeFoldable; use rustc::ty::{self, Ty, TyCtxt}; @@ -16,6 +10,13 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::ItemKind; +use rustc_infer::infer; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::{RegionckMode, TyCtxtInferExt}; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError}; +use rustc_trait_selection::traits::predicate_for_trait_def; +use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt}; pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) { let lang_items = tcx.lang_items(); @@ -306,7 +307,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: DefId) { impl_did, ®ion_scope_tree, &outlives_env, - SuppressRegionErrors::default(), + RegionckMode::default(), ); } } @@ -322,7 +323,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: DefId) { } } -pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo { +pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedInfo { debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); let coerce_unsized_trait = tcx.lang_items().coerce_unsized_trait().unwrap(); @@ -567,7 +568,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn impl_did, ®ion_scope_tree, &outlives_env, - SuppressRegionErrors::default(), + RegionckMode::default(), ); CoerceUnsizedInfo { custom_kind: kind } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index d4c89b7e037..60e5df68b58 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -13,8 +13,8 @@ use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_ast::ast; use rustc_span::Span; -use syntax::ast; /// On-demand query: yields a map containing all types mapped to their inherent impls. pub fn crate_inherent_impls(tcx: TyCtxt<'_>, crate_num: CrateNum) -> &CrateInherentImpls { @@ -283,10 +283,10 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { "no base type found for inherent implementation" ) .span_label(ty.span, "impl requires a base type") - .note(&format!( + .note( "either implement a trait on it or create a newtype \ - to wrap it instead" - )) + to wrap it instead", + ) .emit(); return; } diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index ffea849c4f2..7513759c76b 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -1,10 +1,9 @@ -use crate::namespace::Namespace; -use rustc::traits::{self, SkipLeakCheck}; -use rustc::ty::{AssocItem, TyCtxt}; +use rustc::ty::TyCtxt; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_trait_selection::traits::{self, SkipLeakCheck}; pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, crate_num: CrateNum) { assert_eq!(crate_num, LOCAL_CRATE); @@ -23,18 +22,16 @@ impl InherentOverlapChecker<'tcx> { let impl_items1 = self.tcx.associated_items(impl1); let impl_items2 = self.tcx.associated_items(impl2); - for item1 in &impl_items1[..] { - for item2 in &impl_items2[..] { - // Avoid costly `.modern()` calls as much as possible by doing them as late as we - // can. Compare raw symbols first. - if item1.ident.name == item2.ident.name - && Namespace::from(item1.kind) == Namespace::from(item2.kind) - { - // Symbols and namespace match, compare hygienically. - if item1.ident.modern() == item2.ident.modern() { - return true; - } - } + for item1 in impl_items1.in_definition_order() { + let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).any(|item2| { + // Symbols and namespace match, compare hygienically. + item1.kind.namespace() == item2.kind.namespace() + && item1.ident.normalize_to_macros_2_0() + == item2.ident.normalize_to_macros_2_0() + }); + + if collision { + return true; } } @@ -47,43 +44,44 @@ impl InherentOverlapChecker<'tcx> { impl2: DefId, overlap: traits::OverlapResult<'_>, ) { - let name_and_namespace = - |assoc: &AssocItem| (assoc.ident.modern(), Namespace::from(assoc.kind)); - let impl_items1 = self.tcx.associated_items(impl1); let impl_items2 = self.tcx.associated_items(impl2); - for item1 in &impl_items1[..] { - let (name, namespace) = name_and_namespace(item1); - - for item2 in &impl_items2[..] { - if (name, namespace) == name_and_namespace(item2) { - let mut err = struct_span_err!( - self.tcx.sess, - self.tcx.span_of_impl(item1.def_id).unwrap(), - E0592, - "duplicate definitions with name `{}`", - name - ); - err.span_label( - self.tcx.span_of_impl(item1.def_id).unwrap(), - format!("duplicate definitions for `{}`", name), - ); - err.span_label( - self.tcx.span_of_impl(item2.def_id).unwrap(), - format!("other definition for `{}`", name), - ); - - for cause in &overlap.intercrate_ambiguity_causes { - cause.add_intercrate_ambiguity_hint(&mut err); - } - - if overlap.involves_placeholder { - traits::add_placeholder_note(&mut err); - } + for item1 in impl_items1.in_definition_order() { + let collision = impl_items2.filter_by_name_unhygienic(item1.ident.name).find(|item2| { + // Symbols and namespace match, compare hygienically. + item1.kind.namespace() == item2.kind.namespace() + && item1.ident.normalize_to_macros_2_0() + == item2.ident.normalize_to_macros_2_0() + }); + + if let Some(item2) = collision { + let name = item1.ident.normalize_to_macros_2_0(); + let mut err = struct_span_err!( + self.tcx.sess, + self.tcx.span_of_impl(item1.def_id).unwrap(), + E0592, + "duplicate definitions with name `{}`", + name + ); + err.span_label( + self.tcx.span_of_impl(item1.def_id).unwrap(), + format!("duplicate definitions for `{}`", name), + ); + err.span_label( + self.tcx.span_of_impl(item2.def_id).unwrap(), + format!("other definition for `{}`", name), + ); + + for cause in &overlap.intercrate_ambiguity_causes { + cause.add_intercrate_ambiguity_hint(&mut err); + } - err.emit(); + if overlap.involves_placeholder { + traits::add_placeholder_note(&mut err); } + + err.emit(); } } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 1526182576c..27b2c19499c 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -5,12 +5,12 @@ // done by the orphan and overlap modules. Then we build up various // mappings. That mapping code resides here. -use rustc::traits; use rustc::ty::query::Providers; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc_errors::struct_span_err; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_span::Span; +use rustc_trait_selection::traits; mod builtin; mod inherent_impls; @@ -76,6 +76,22 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt<'_>, impl_def_id: DefId, tra return; } + if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = + tcx.trait_def(trait_def_id).specialization_kind + { + if !tcx.features().specialization && !tcx.features().min_specialization { + let span = impl_header_span(tcx, impl_def_id); + tcx.sess + .struct_span_err( + span, + "implementing `rustc_specialization_trait` traits is unstable", + ) + .help("add `#![feature(min_specialization)]` to the crate attributes to enable") + .emit(); + return; + } + } + let trait_name = if did == li.fn_trait() { "Fn" } else if did == li.fn_mut_trait() { diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 80521666476..fc77aad8688 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -1,11 +1,12 @@ //! Orphan checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use rustc::traits; use rustc::ty::{self, TyCtxt}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_trait_selection::traits; pub fn check(tcx: TyCtxt<'_>) { let mut orphan = OrphanChecker { tcx }; @@ -32,8 +33,8 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { ); let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap(); let trait_def_id = trait_ref.def_id; - let cm = self.tcx.sess.source_map(); - let sp = cm.def_span(item.span); + let sm = self.tcx.sess.source_map(); + let sp = sm.def_span(item.span); match traits::orphan_check(self.tcx, def_id) { Ok(()) => {} Err(traits::OrphanCheckErr::NonLocalInputType(tys)) => { @@ -173,7 +174,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { // impl !Send for (A, B) { } // ``` // - // This final impl is legal according to the orpan + // This final impl is legal according to the orphan // rules, but it invalidates the reasoning from // `two_foos` above. debug!( diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index a6044217403..3b25f67aacc 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -69,11 +69,11 @@ impl UnsafetyChecker<'tcx> { .emit(); } - (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative) => { + (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => { // Reported in AST validation self.tcx.sess.delay_span_bug(item.span, "unsafe negative impl"); } - (_, _, Unsafety::Normal, hir::ImplPolarity::Negative) + (_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_)) | (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive) | (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive) | (Unsafety::Normal, None, Unsafety::Normal, _) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 5349c324ad8..7145b948f2f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! "Collection" is the process of determining the type and other external //! details of each item in Rust. Collection is specifically concerned //! with *inter-procedural* things -- for example, for a function @@ -19,36 +17,36 @@ use crate::astconv::{AstConv, Bounds, SizedByDefault}; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::constrained_generic_params as cgp; -use crate::lint; use crate::middle::lang_items; use crate::middle::resolve_lifetime as rl; use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::Map; use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc::mir::mono::Linkage; -use rustc::session::parse::feature_err; -use rustc::traits; use rustc::ty::query::Providers; -use rustc::ty::subst::GenericArgKind; use rustc::ty::subst::{InternalSubsts, Subst}; use rustc::ty::util::Discr; use rustc::ty::util::IntTypeExt; -use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, WithConstness}; -use rustc::ty::{ReprOptions, ToPredicate}; +use rustc::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt}; +use rustc::ty::{ReprOptions, ToPredicate, WithConstness}; +use rustc_ast::ast; +use rustc_ast::ast::{Ident, MetaItemKind}; use rustc_attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Applicability, StashKey}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{GenericParamKind, Node, Unsafety}; +use rustc_session::lint; +use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; -use syntax::ast; -use syntax::ast::{Ident, MetaItemKind}; + +mod type_of; struct OnlySelfBounds(bool); @@ -64,7 +62,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) { pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { - type_of, + type_of: type_of::type_of, generics_of, predicates_of, predicates_defined_on, @@ -78,6 +76,7 @@ pub fn provide(providers: &mut Providers<'_>) { impl_polarity, is_foreign_item, static_mutability, + generator_kind, codegen_fn_attrs, collect_mod_item_types, ..*providers @@ -106,9 +105,9 @@ pub struct ItemCtxt<'tcx> { crate struct PlaceholderHirTyCollector(crate Vec); impl<'v> Visitor<'v> for PlaceholderHirTyCollector { - type Map = Map<'v>; + type Map = intravisit::ErasedMap<'v>; - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { @@ -152,7 +151,7 @@ crate fn placeholder_type_error( .unwrap_or(&"ParamName"); let mut sugg: Vec<_> = - placeholder_types.iter().map(|sp| (*sp, type_name.to_string())).collect(); + placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect(); if generics.is_empty() { sugg.push((span, format!("<{}>", type_name))); } else if let Some(arg) = generics.iter().find(|arg| match arg.name { @@ -161,7 +160,7 @@ crate fn placeholder_type_error( }) { // Account for `_` already present in cases like `struct S<_>(_);` and suggest // `struct S(T);` instead of `struct S<_, T>(T);`. - sugg.push((arg.span, format!("{}", type_name))); + sugg.push((arg.span, (*type_name).to_string())); } else { sugg.push(( generics.iter().last().unwrap().span.shrink_to_hi(), @@ -202,8 +201,8 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { type Map = Map<'tcx>; - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir()) + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.tcx.hir()) } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { @@ -371,10 +370,12 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { hir::ItemKind::Enum(_, generics) | hir::ItemKind::Struct(_, generics) | hir::ItemKind::Union(_, generics) => { - // FIXME: look for an appropriate lt name if `'a` is already used + let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics); let (lt_sp, sugg) = match &generics.params[..] { - [] => (generics.span, "<'a>".to_string()), - [bound, ..] => (bound.span.shrink_to_lo(), "'a, ".to_string()), + [] => (generics.span, format!("<{}>", lt_name)), + [bound, ..] => { + (bound.span.shrink_to_lo(), format!("{}, ", lt_name)) + } }; let suggestions = vec![ (lt_sp, sugg), @@ -389,7 +390,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { ty::EarlyBoundRegion { def_id: item_def_id, index: 0, - name: Symbol::intern("'a"), + name: Symbol::intern(<_name), }, )) }) @@ -447,6 +448,43 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } } +/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present. +fn get_new_lifetime_name<'tcx>( + tcx: TyCtxt<'tcx>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + generics: &hir::Generics<'tcx>, +) -> String { + let existing_lifetimes = tcx + .collect_referenced_late_bound_regions(&poly_trait_ref) + .into_iter() + .filter_map(|lt| { + if let ty::BoundRegion::BrNamed(_, name) = lt { + Some(name.as_str().to_string()) + } else { + None + } + }) + .chain(generics.params.iter().filter_map(|param| { + if let hir::GenericParamKind::Lifetime { .. } = ¶m.kind { + Some(param.name.ident().as_str().to_string()) + } else { + None + } + })) + .collect::>(); + + let a_to_z_repeat_n = |n| { + (b'a'..=b'z').map(move |c| { + let mut s = '\''.to_string(); + s.extend(std::iter::repeat(char::from(c)).take(n)); + s + }) + }; + + // If all single char lifetime names are present, we wrap around and double the chars. + (1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap() +} + /// Returns the predicates defined on `item_def_id` of the form /// `X: Foo` where `X` is the type parameter `def_id`. fn type_param_predicates( @@ -677,13 +715,21 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::HirId) { tcx.generics_of(def_id); match trait_item.kind { - hir::TraitItemKind::Const(..) - | hir::TraitItemKind::Type(_, Some(_)) - | hir::TraitItemKind::Method(..) => { + hir::TraitItemKind::Fn(..) => { + tcx.type_of(def_id); + tcx.fn_sig(def_id); + } + + hir::TraitItemKind::Const(.., Some(_)) => { tcx.type_of(def_id); - if let hir::TraitItemKind::Method(..) = trait_item.kind { - tcx.fn_sig(def_id); - } + } + + hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(_, Some(_)) => { + tcx.type_of(def_id); + // Account for `const C: _;` and `type T = _;`. + let mut visitor = PlaceholderHirTyCollector::default(); + visitor.visit_trait_item(trait_item); + placeholder_type_error(tcx, DUMMY_SP, &[], visitor.0, false); } hir::TraitItemKind::Type(_, None) => {} @@ -697,8 +743,18 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::HirId) { tcx.generics_of(def_id); tcx.type_of(def_id); tcx.predicates_of(def_id); - if let hir::ImplItemKind::Method(..) = tcx.hir().expect_impl_item(impl_item_id).kind { - tcx.fn_sig(def_id); + let impl_item = tcx.hir().expect_impl_item(impl_item_id); + match impl_item.kind { + hir::ImplItemKind::Fn(..) => { + tcx.fn_sig(def_id); + } + hir::ImplItemKind::TyAlias(_) | hir::ImplItemKind::OpaqueTy(_) => { + // Account for `type T = _;` + let mut visitor = PlaceholderHirTyCollector::default(); + visitor.visit_impl_item(impl_item); + placeholder_type_error(tcx, DUMMY_SP, &[], visitor.0, false); + } + hir::ImplItemKind::Const(..) => {} } } @@ -772,7 +828,7 @@ fn convert_variant( .iter() .map(|f| { let fid = tcx.hir().local_def_id(f.hir_id); - let dup_span = seen_fields.get(&f.ident.modern()).cloned(); + let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned(); if let Some(prev_span) = dup_span { struct_span_err!( tcx.sess, @@ -785,7 +841,7 @@ fn convert_variant( .span_label(prev_span, format!("`{}` first declared here", f.ident)) .emit(); } else { - seen_fields.insert(f.ident.modern(), f.span); + seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span); } ty::FieldDef { @@ -969,15 +1025,30 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TraitDef { .struct_span_err( item.span, "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ - which traits can use parenthetical notation", + which traits can use parenthetical notation", ) .help("add `#![feature(unboxed_closures)]` to the crate attributes to use it") .emit(); } let is_marker = tcx.has_attr(def_id, sym::marker); + let spec_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) { + ty::trait_def::TraitSpecializationKind::Marker + } else if tcx.has_attr(def_id, sym::rustc_specialization_trait) { + ty::trait_def::TraitSpecializationKind::AlwaysApplicable + } else { + ty::trait_def::TraitSpecializationKind::None + }; let def_path_hash = tcx.def_path_hash(def_id); - let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, is_marker, def_path_hash); + let def = ty::TraitDef::new( + def_id, + unsafety, + paren_sugar, + is_auto, + is_marker, + spec_kind, + def_path_hash, + ); tcx.arena.alloc(def) } @@ -989,9 +1060,9 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option for LateBoundRegionsDetector<'tcx> { - type Map = Map<'tcx>; + type Map = intravisit::ErasedMap<'tcx>; - fn nested_visit_map(&mut self) -> NestedVisitorMap<'_, Self::Map> { + fn nested_visit_map(&mut self) -> NestedVisitorMap { NestedVisitorMap::None } @@ -1065,13 +1136,13 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option match item.kind { - hir::TraitItemKind::Method(ref sig, _) => { + hir::TraitItemKind::Fn(ref sig, _) => { has_late_bound_regions(tcx, &item.generics, &sig.decl) } _ => None, }, Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::Method(ref sig, _) => { + hir::ImplItemKind::Fn(ref sig, _) => { has_late_bound_regions(tcx, &item.generics, &sig.decl) } _ => None, @@ -1232,7 +1303,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id); - // Now create the real type parameters. + // Now create the real type and const parameters. let type_start = own_start - has_self as u32 + params.len() as u32; let mut i = 0; params.extend(ast_generics.params.iter().filter_map(|param| { @@ -1245,10 +1316,10 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { param.hir_id, param.span, |lint| { - lint.build(&format!( + lint.build( "defaults for type parameters are only allowed in \ - `struct`, `enum`, `type`, or `trait` definitions." - )) + `struct`, `enum`, `type`, or `trait` definitions.", + ) .emit(); }, ); @@ -1329,601 +1400,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { }) } -fn report_assoc_ty_on_inherent_impl(tcx: TyCtxt<'_>, span: Span) { - struct_span_err!( - tcx.sess, - span, - E0202, - "associated types are not yet supported in inherent impls (see #8995)" - ) - .emit(); -} - -fn infer_placeholder_type( - tcx: TyCtxt<'_>, - def_id: DefId, - body_id: hir::BodyId, - span: Span, - item_ident: Ident, -) -> Ty<'_> { - let ty = tcx.diagnostic_only_typeck_tables_of(def_id).node_type(body_id.hir_id); - - // If this came from a free `const` or `static mut?` item, - // then the user may have written e.g. `const A = 42;`. - // In this case, the parser has stashed a diagnostic for - // us to improve in typeck so we do that now. - match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) { - Some(mut err) => { - // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. - // We are typeck and have the real type, so remove that and suggest the actual type. - err.suggestions.clear(); - err.span_suggestion( - span, - "provide a type for the item", - format!("{}: {}", item_ident, ty), - Applicability::MachineApplicable, - ) - .emit(); - } - None => { - let mut diag = bad_placeholder_type(tcx, vec![span]); - if ty != tcx.types.err { - diag.span_suggestion( - span, - "replace `_` with the correct type", - ty.to_string(), - Applicability::MaybeIncorrect, - ); - } - diag.emit(); - } - } - - ty -} - -fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { - use rustc_hir::*; - - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - - let icx = ItemCtxt::new(tcx, def_id); - - match tcx.hir().get(hir_id) { - Node::TraitItem(item) => match item.kind { - TraitItemKind::Method(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs) - } - TraitItemKind::Const(ref ty, body_id) => body_id - .and_then(|body_id| { - if is_suggestable_infer_ty(ty) { - Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)) - } else { - None - } - }) - .unwrap_or_else(|| icx.to_ty(ty)), - TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty), - TraitItemKind::Type(_, None) => { - span_bug!(item.span, "associated type missing default"); - } - }, - - Node::ImplItem(item) => match item.kind { - ImplItemKind::Method(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs) - } - ImplItemKind::Const(ref ty, body_id) => { - if is_suggestable_infer_ty(ty) { - infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) - } else { - icx.to_ty(ty) - } - } - ImplItemKind::OpaqueTy(_) => { - if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() { - report_assoc_ty_on_inherent_impl(tcx, item.span); - } - - find_opaque_ty_constraints(tcx, def_id) - } - ImplItemKind::TyAlias(ref ty) => { - if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() { - report_assoc_ty_on_inherent_impl(tcx, item.span); - } - - icx.to_ty(ty) - } - }, - - Node::Item(item) => { - match item.kind { - ItemKind::Static(ref ty, .., body_id) | ItemKind::Const(ref ty, body_id) => { - if is_suggestable_infer_ty(ty) { - infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) - } else { - icx.to_ty(ty) - } - } - ItemKind::TyAlias(ref self_ty, _) | ItemKind::Impl { ref self_ty, .. } => { - icx.to_ty(self_ty) - } - ItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs) - } - ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { - let def = tcx.adt_def(def_id); - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_adt(def, substs) - } - ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => { - find_opaque_ty_constraints(tcx, def_id) - } - // Opaque types desugared from `impl Trait`. - ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(owner), .. }) => { - tcx.typeck_tables_of(owner) - .concrete_opaque_types - .get(&def_id) - .map(|opaque| opaque.concrete_type) - .unwrap_or_else(|| { - // This can occur if some error in the - // owner fn prevented us from populating - // the `concrete_opaque_types` table. - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "owner {:?} has no opaque type for {:?} in its tables", - owner, def_id, - ), - ); - tcx.types.err - }) - } - ItemKind::Trait(..) - | ItemKind::TraitAlias(..) - | ItemKind::Mod(..) - | ItemKind::ForeignMod(..) - | ItemKind::GlobalAsm(..) - | ItemKind::ExternCrate(..) - | ItemKind::Use(..) => { - span_bug!( - item.span, - "compute_type_of_item: unexpected item type: {:?}", - item.kind - ); - } - } - } - - Node::ForeignItem(foreign_item) => match foreign_item.kind { - ForeignItemKind::Fn(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs) - } - ForeignItemKind::Static(ref t, _) => icx.to_ty(t), - ForeignItemKind::Type => tcx.mk_foreign(def_id), - }, - - Node::Ctor(&ref def) | Node::Variant(hir::Variant { data: ref def, .. }) => match *def { - VariantData::Unit(..) | VariantData::Struct(..) => { - tcx.type_of(tcx.hir().get_parent_did(hir_id)) - } - VariantData::Tuple(..) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_fn_def(def_id, substs) - } - }, - - Node::Field(field) => icx.to_ty(&field.ty), - - Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., gen), .. }) => { - if gen.is_some() { - return tcx.typeck_tables_of(def_id).node_type(hir_id); - } - - let substs = InternalSubsts::identity_for_item(tcx, def_id); - tcx.mk_closure(def_id, substs) - } - - Node::AnonConst(_) => { - let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); - match parent_node { - Node::Ty(&hir::Ty { kind: hir::TyKind::Array(_, ref constant), .. }) - | Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref constant), .. }) - | Node::Expr(&hir::Expr { kind: ExprKind::Repeat(_, ref constant), .. }) - if constant.hir_id == hir_id => - { - tcx.types.usize - } - - Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { - tcx.adt_def(tcx.hir().get_parent_did(hir_id)).repr.discr_type().to_ty(tcx) - } - - Node::Ty(&hir::Ty { kind: hir::TyKind::Path(_), .. }) - | Node::Expr(&hir::Expr { kind: ExprKind::Struct(..), .. }) - | Node::Expr(&hir::Expr { kind: ExprKind::Path(_), .. }) - | Node::TraitRef(..) => { - let path = match parent_node { - Node::Ty(&hir::Ty { - kind: hir::TyKind::Path(QPath::Resolved(_, ref path)), - .. - }) - | Node::Expr(&hir::Expr { - kind: ExprKind::Path(QPath::Resolved(_, ref path)), - .. - }) => Some(&**path), - Node::Expr(&hir::Expr { kind: ExprKind::Struct(ref path, ..), .. }) => { - if let QPath::Resolved(_, ref path) = **path { - Some(&**path) - } else { - None - } - } - Node::TraitRef(&hir::TraitRef { ref path, .. }) => Some(&**path), - _ => None, - }; - - if let Some(path) = path { - let arg_index = path - .segments - .iter() - .filter_map(|seg| seg.args.as_ref()) - .map(|generic_args| generic_args.args.as_ref()) - .find_map(|args| { - args.iter() - .filter(|arg| arg.is_const()) - .enumerate() - .filter(|(_, arg)| arg.id() == hir_id) - .map(|(index, _)| index) - .next() - }) - .unwrap_or_else(|| { - bug!("no arg matching AnonConst in path"); - }); - - // We've encountered an `AnonConst` in some path, so we need to - // figure out which generic parameter it corresponds to and return - // the relevant type. - let generics = match path.res { - Res::Def(DefKind::Ctor(..), def_id) => { - tcx.generics_of(tcx.parent(def_id).unwrap()) - } - Res::Def(_, def_id) => tcx.generics_of(def_id), - Res::Err => return tcx.types.err, - res => { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!("unexpected const parent path def {:?}", res,), - ); - return tcx.types.err; - } - }; - - generics - .params - .iter() - .filter(|param| { - if let ty::GenericParamDefKind::Const = param.kind { - true - } else { - false - } - }) - .nth(arg_index) - .map(|param| tcx.type_of(param.def_id)) - // This is no generic parameter associated with the arg. This is - // probably from an extra arg where one is not needed. - .unwrap_or(tcx.types.err) - } else { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!("unexpected const parent path {:?}", parent_node,), - ); - return tcx.types.err; - } - } - - x => { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!("unexpected const parent in type_of_def_id(): {:?}", x), - ); - tcx.types.err - } - } - } - - Node::GenericParam(param) => match ¶m.kind { - hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty), - hir::GenericParamKind::Const { ty: ref hir_ty, .. } => { - let ty = icx.to_ty(hir_ty); - if !tcx.features().const_compare_raw_pointers { - let err = match ty.peel_refs().kind { - ty::FnPtr(_) => Some("function pointers"), - ty::RawPtr(_) => Some("raw pointers"), - _ => None, - }; - if let Some(unsupported_type) = err { - feature_err( - &tcx.sess.parse_sess, - sym::const_compare_raw_pointers, - hir_ty.span, - &format!( - "using {} as const generic parameters is unstable", - unsupported_type - ), - ) - .emit(); - }; - } - if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty) - .is_some() - { - struct_span_err!( - tcx.sess, - hir_ty.span, - E0741, - "the types of const generic parameters must derive `PartialEq` and `Eq`", - ) - .span_label( - hir_ty.span, - format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty), - ) - .emit(); - } - ty - } - x => bug!("unexpected non-type Node::GenericParam: {:?}", x), - }, - - x => { - bug!("unexpected sort of node in type_of_def_id(): {:?}", x); - } - } -} - -fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { - use rustc_hir::{ImplItem, Item, TraitItem}; - - debug!("find_opaque_ty_constraints({:?})", def_id); - - struct ConstraintLocator<'tcx> { - tcx: TyCtxt<'tcx>, - def_id: DefId, - // (first found type span, actual type, mapping from the opaque type's generic - // parameters to the concrete type's generic parameters) - // - // The mapping is an index for each use site of a generic parameter in the concrete type - // - // The indices index into the generic parameters on the opaque type. - found: Option<(Span, Ty<'tcx>, Vec)>, - } - - impl ConstraintLocator<'tcx> { - fn check(&mut self, def_id: DefId) { - // Don't try to check items that cannot possibly constrain the type. - if !self.tcx.has_typeck_tables(def_id) { - debug!( - "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`: no tables", - self.def_id, def_id, - ); - return; - } - let ty = self.tcx.typeck_tables_of(def_id).concrete_opaque_types.get(&self.def_id); - if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty { - debug!( - "find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}", - self.def_id, def_id, ty, - ); - - // FIXME(oli-obk): trace the actual span from inference to improve errors. - let span = self.tcx.def_span(def_id); - // used to quickly look up the position of a generic parameter - let mut index_map: FxHashMap = FxHashMap::default(); - // Skipping binder is ok, since we only use this to find generic parameters and - // their positions. - for (idx, subst) in substs.iter().enumerate() { - if let GenericArgKind::Type(ty) = subst.unpack() { - if let ty::Param(p) = ty.kind { - if index_map.insert(p, idx).is_some() { - // There was already an entry for `p`, meaning a generic parameter - // was used twice. - self.tcx.sess.span_err( - span, - &format!( - "defining opaque type use restricts opaque \ - type by using the generic parameter `{}` twice", - p, - ), - ); - return; - } - } else { - self.tcx.sess.delay_span_bug( - span, - &format!( - "non-defining opaque ty use in defining scope: {:?}, {:?}", - concrete_type, substs, - ), - ); - } - } - } - // Compute the index within the opaque type for each generic parameter used in - // the concrete type. - let indices = concrete_type - .subst(self.tcx, substs) - .walk() - .filter_map(|t| match &t.kind { - ty::Param(p) => Some(*index_map.get(p).unwrap()), - _ => None, - }) - .collect(); - let is_param = |ty: Ty<'_>| match ty.kind { - ty::Param(_) => true, - _ => false, - }; - let bad_substs: Vec<_> = substs - .iter() - .enumerate() - .filter_map(|(i, k)| { - if let GenericArgKind::Type(ty) = k.unpack() { Some((i, ty)) } else { None } - }) - .filter(|(_, ty)| !is_param(ty)) - .collect(); - - if !bad_substs.is_empty() { - let identity_substs = InternalSubsts::identity_for_item(self.tcx, self.def_id); - for (i, bad_subst) in bad_substs { - self.tcx.sess.span_err( - span, - &format!( - "defining opaque type use does not fully define opaque type: \ - generic parameter `{}` is specified as concrete type `{}`", - identity_substs.type_at(i), - bad_subst - ), - ); - } - } else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found { - let mut ty = concrete_type.walk().fuse(); - let mut p_ty = prev_ty.walk().fuse(); - let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.kind, &p.kind) { - // Type parameters are equal to any other type parameter for the purpose of - // concrete type equality, as it is possible to obtain the same type just - // by passing matching parameters to a function. - (ty::Param(_), ty::Param(_)) => true, - _ => t == p, - }); - if !iter_eq || ty.next().is_some() || p_ty.next().is_some() { - debug!("find_opaque_ty_constraints: span={:?}", span); - // Found different concrete types for the opaque type. - let mut err = self.tcx.sess.struct_span_err( - span, - "concrete type differs from previous defining opaque type use", - ); - err.span_label( - span, - format!("expected `{}`, got `{}`", prev_ty, concrete_type), - ); - err.span_note(prev_span, "previous use here"); - err.emit(); - } else if indices != *prev_indices { - // Found "same" concrete types, but the generic parameter order differs. - let mut err = self.tcx.sess.struct_span_err( - span, - "concrete type's generic parameters differ from previous defining use", - ); - use std::fmt::Write; - let mut s = String::new(); - write!(s, "expected [").unwrap(); - let list = |s: &mut String, indices: &Vec| { - let mut indices = indices.iter().cloned(); - if let Some(first) = indices.next() { - write!(s, "`{}`", substs[first]).unwrap(); - for i in indices { - write!(s, ", `{}`", substs[i]).unwrap(); - } - } - }; - list(&mut s, prev_indices); - write!(s, "], got [").unwrap(); - list(&mut s, &indices); - write!(s, "]").unwrap(); - err.span_label(span, s); - err.span_note(prev_span, "previous use here"); - err.emit(); - } - } else { - self.found = Some((span, concrete_type, indices)); - } - } else { - debug!( - "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`", - self.def_id, def_id, - ); - } - } - } - - impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> { - type Map = Map<'tcx>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> { - intravisit::NestedVisitorMap::All(&self.tcx.hir()) - } - fn visit_item(&mut self, it: &'tcx Item<'tcx>) { - debug!("find_existential_constraints: visiting {:?}", it); - let def_id = self.tcx.hir().local_def_id(it.hir_id); - // The opaque type itself or its children are not within its reveal scope. - if def_id != self.def_id { - self.check(def_id); - intravisit::walk_item(self, it); - } - } - fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { - debug!("find_existential_constraints: visiting {:?}", it); - let def_id = self.tcx.hir().local_def_id(it.hir_id); - // The opaque type itself or its children are not within its reveal scope. - if def_id != self.def_id { - self.check(def_id); - intravisit::walk_impl_item(self, it); - } - } - fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { - debug!("find_existential_constraints: visiting {:?}", it); - let def_id = self.tcx.hir().local_def_id(it.hir_id); - self.check(def_id); - intravisit::walk_trait_item(self, it); - } - } - - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - let scope = tcx.hir().get_defining_scope(hir_id); - let mut locator = ConstraintLocator { def_id, tcx, found: None }; - - debug!("find_opaque_ty_constraints: scope={:?}", scope); - - if scope == hir::CRATE_HIR_ID { - intravisit::walk_crate(&mut locator, tcx.hir().krate()); - } else { - debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope)); - match tcx.hir().get(scope) { - // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods - // This allows our visitor to process the defining item itself, causing - // it to pick up any 'sibling' defining uses. - // - // For example, this code: - // ``` - // fn foo() { - // type Blah = impl Debug; - // let my_closure = || -> Blah { true }; - // } - // ``` - // - // requires us to explicitly process `foo()` in order - // to notice the defining usage of `Blah`. - Node::Item(ref it) => locator.visit_item(it), - Node::ImplItem(ref it) => locator.visit_impl_item(it), - Node::TraitItem(ref it) => locator.visit_trait_item(it), - other => bug!("{:?} is not a valid scope for an opaque type item", other), - } - } - - match locator.found { - Some((_, ty, _)) => ty, - None => { - let span = tcx.def_span(def_id); - tcx.sess.span_err(span, "could not find defining uses"); - tcx.types.err - } - } -} - fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool { generic_args .iter() @@ -1934,7 +1410,7 @@ fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool { .any(is_suggestable_infer_ty) } -/// Whether `ty` is a type with `_` placeholders that can be infered. Used in diagnostics only to +/// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to /// use inference to provide suggestions for the appropriate type if possible. fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool { use hir::TyKind::*; @@ -1957,8 +1433,8 @@ fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool { } } -pub fn get_infer_ret_ty(output: &'hir hir::FunctionRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> { - if let hir::FunctionRetTy::Return(ref ty) = output { +pub fn get_infer_ret_ty(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> { + if let hir::FnRetTy::Return(ref ty) = output { if is_suggestable_infer_ty(ty) { return Some(&**ty); } @@ -1976,12 +1452,12 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { match tcx.hir().get(hir_id) { TraitItem(hir::TraitItem { - kind: TraitItemKind::Method(sig, TraitMethod::Provided(_)), + kind: TraitItemKind::Fn(sig, TraitFn::Provided(_)), ident, generics, .. }) - | ImplItem(hir::ImplItem { kind: ImplItemKind::Method(sig, _), ident, generics, .. }) + | ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), ident, generics, .. }) | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), ident, .. }) => { match get_infer_ret_ty(&sig.decl.output) { Some(ty) => { @@ -2013,7 +1489,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { } TraitItem(hir::TraitItem { - kind: TraitItemKind::Method(FnSig { header, decl }, _), + kind: TraitItemKind::Fn(FnSig { header, decl }, _), ident, generics, .. @@ -2087,7 +1563,7 @@ fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity { let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl); let item = tcx.hir().expect_item(hir_id); match &item.kind { - hir::ItemKind::Impl { polarity: hir::ImplPolarity::Negative, .. } => { + hir::ItemKind::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => { if is_rustc_reservation { tcx.sess.span_err(item.span, "reservation impls can't be negative"); } @@ -2185,7 +1661,6 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { /// Returns a list of user-specified type predicates for the definition with ID `def_id`. /// N.B., this does not include any implied/inferred constraints. fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { - use rustc_data_structures::fx::FxHashSet; use rustc_hir::*; debug!("explicit_predicates_of(def_id={:?})", def_id); @@ -2665,7 +2140,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( ast_ty.span, &format!( "use of SIMD type `{}` in FFI is highly experimental and \ - may result in invalid code", + may result in invalid code", tcx.hir().hir_to_pretty_string(ast_ty.hir_id) ), ) @@ -2676,7 +2151,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( for (input, ty) in decl.inputs.iter().zip(*fty.inputs().skip_binder()) { check(&input, ty) } - if let hir::FunctionRetTy::Return(ref ty) = decl.output { + if let hir::FnRetTy::Return(ref ty) = decl.output { check(&ty, *fty.output().skip_binder()) } } @@ -2704,6 +2179,17 @@ fn static_mutability(tcx: TyCtxt<'_>, def_id: DefId) -> Option } } +fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + match tcx.hir().get_if_local(def_id) { + Some(Node::Expr(&rustc_hir::Expr { + kind: rustc_hir::ExprKind::Closure(_, _, body_id, _, _), + .. + })) => tcx.hir().body(body_id).generator_kind(), + Some(_) => None, + _ => bug!("generator_kind applied to non-local def-id {:?}", def_id), + } +} + fn from_target_feature( tcx: TyCtxt<'_>, id: DefId, @@ -2753,7 +2239,7 @@ fn from_target_feature( item.span(), format!("`{}` is not valid for this target", feature), ); - if feature.starts_with("+") { + if feature.starts_with('+') { let valid = whitelist.contains_key(&feature[1..]); if valid { err.help("consider removing the leading `+` in the feature name"); @@ -2765,7 +2251,7 @@ fn from_target_feature( }; // Only allow features whose feature gates have been enabled. - let allowed = match feature_gate.as_ref().map(|s| *s) { + let allowed = match feature_gate.as_ref().copied() { Some(sym::arm_target_feature) => rust_features.arm_target_feature, Some(sym::aarch64_target_feature) => rust_features.aarch64_target_feature, Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature, @@ -2870,21 +2356,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; } else if attr.check_name(sym::rustc_std_internal_symbol) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; - } else if attr.check_name(sym::no_debug) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_DEBUG; } else if attr.check_name(sym::used) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; } else if attr.check_name(sym::thread_local) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; } else if attr.check_name(sym::track_caller) { - if tcx.fn_sig(id).abi() != abi::Abi::Rust { + if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust { struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") .emit(); } codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } else if attr.check_name(sym::export_name) { if let Some(s) = attr.value_str() { - if s.as_str().contains("\0") { + if s.as_str().contains('\0') { // `#[export_name = ...]` will be converted to a null-terminated string, // so it may not contain any null characters. struct_span_err!( @@ -2898,7 +2382,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(s); } } else if attr.check_name(sym::target_feature) { - if tcx.fn_sig(id).unsafety() == Unsafety::Normal { + if tcx.is_closure(id) || tcx.fn_sig(id).unsafety() == Unsafety::Normal { let msg = "`#[target_feature(..)]` can only be applied to `unsafe` functions"; tcx.sess .struct_span_err(attr.span, msg) @@ -3028,7 +2512,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { // purpose functions as they wouldn't have the right target features // enabled. For that reason we also forbid #[inline(always)] as it can't be // respected. - if codegen_fn_attrs.target_features.len() > 0 { + if !codegen_fn_attrs.target_features.is_empty() { if codegen_fn_attrs.inline == InlineAttr::Always { if let Some(span) = inline_span { tcx.sess.span_err( @@ -3083,7 +2567,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { - use syntax::ast::{Lit, LitIntType, LitKind}; + use rustc_ast::ast::{Lit, LitIntType, LitKind}; let meta_item_list = attr.meta_item_list(); let meta_item_list: Option<&[ast::NestedMetaItem]> = meta_item_list.as_ref().map(Vec::as_ref); let sole_meta_list = match meta_item_list { diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs new file mode 100644 index 00000000000..41c205bc11b --- /dev/null +++ b/src/librustc_typeck/collect/type_of.rs @@ -0,0 +1,661 @@ +use rustc::hir::map::Map; +use rustc::ty::subst::{GenericArgKind, InternalSubsts, Subst}; +use rustc::ty::util::IntTypeExt; +use rustc::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable}; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{struct_span_err, Applicability, StashKey}; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::intravisit; +use rustc_hir::intravisit::Visitor; +use rustc_hir::Node; +use rustc_session::parse::feature_err; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::traits; + +use super::ItemCtxt; +use super::{bad_placeholder_type, is_suggestable_infer_ty}; + +pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { + use rustc_hir::*; + + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + + let icx = ItemCtxt::new(tcx, def_id); + + match tcx.hir().get(hir_id) { + Node::TraitItem(item) => match item.kind { + TraitItemKind::Fn(..) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs) + } + TraitItemKind::Const(ref ty, body_id) => body_id + .and_then(|body_id| { + if is_suggestable_infer_ty(ty) { + Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)) + } else { + None + } + }) + .unwrap_or_else(|| icx.to_ty(ty)), + TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty), + TraitItemKind::Type(_, None) => { + span_bug!(item.span, "associated type missing default"); + } + }, + + Node::ImplItem(item) => match item.kind { + ImplItemKind::Fn(..) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs) + } + ImplItemKind::Const(ref ty, body_id) => { + if is_suggestable_infer_ty(ty) { + infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) + } else { + icx.to_ty(ty) + } + } + ImplItemKind::OpaqueTy(_) => { + if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() { + report_assoc_ty_on_inherent_impl(tcx, item.span); + } + + find_opaque_ty_constraints(tcx, def_id) + } + ImplItemKind::TyAlias(ref ty) => { + if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() { + report_assoc_ty_on_inherent_impl(tcx, item.span); + } + + icx.to_ty(ty) + } + }, + + Node::Item(item) => { + match item.kind { + ItemKind::Static(ref ty, .., body_id) | ItemKind::Const(ref ty, body_id) => { + if is_suggestable_infer_ty(ty) { + infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident) + } else { + icx.to_ty(ty) + } + } + ItemKind::TyAlias(ref self_ty, _) | ItemKind::Impl { ref self_ty, .. } => { + icx.to_ty(self_ty) + } + ItemKind::Fn(..) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs) + } + ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { + let def = tcx.adt_def(def_id); + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_adt(def, substs) + } + ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: None, .. }) => { + find_opaque_ty_constraints(tcx, def_id) + } + // Opaque types desugared from `impl Trait`. + ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), origin, .. }) => { + let concrete_types = match origin { + OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => { + &tcx.mir_borrowck(owner).concrete_opaque_types + } + OpaqueTyOrigin::Misc => { + // We shouldn't leak borrowck results through impl trait in bindings. + // For example, we shouldn't be able to tell if `x` in + // `let x: impl Sized + 'a = &()` has type `&'static ()` or `&'a ()`. + &tcx.typeck_tables_of(owner).concrete_opaque_types + } + OpaqueTyOrigin::TypeAlias => { + span_bug!(item.span, "Type alias impl trait shouldn't have an owner") + } + }; + let concrete_ty = concrete_types + .get(&def_id) + .map(|opaque| opaque.concrete_type) + .unwrap_or_else(|| { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "owner {:?} has no opaque type for {:?} in its tables", + owner, def_id, + ), + ); + if tcx.typeck_tables_of(owner).tainted_by_errors { + // Some error in the + // owner fn prevented us from populating + // the `concrete_opaque_types` table. + tcx.types.err + } else { + // We failed to resolve the opaque type or it + // resolves to itself. Return the non-revealed + // type, which should result in E0720. + tcx.mk_opaque( + def_id, + InternalSubsts::identity_for_item(tcx, def_id), + ) + } + }); + debug!("concrete_ty = {:?}", concrete_ty); + if concrete_ty.has_erased_regions() { + // FIXME(impl_trait_in_bindings) Handle this case. + tcx.sess.span_fatal( + item.span, + "lifetimes in impl Trait types in bindings are not currently supported", + ); + } + concrete_ty + } + ItemKind::Trait(..) + | ItemKind::TraitAlias(..) + | ItemKind::Mod(..) + | ItemKind::ForeignMod(..) + | ItemKind::GlobalAsm(..) + | ItemKind::ExternCrate(..) + | ItemKind::Use(..) => { + span_bug!( + item.span, + "compute_type_of_item: unexpected item type: {:?}", + item.kind + ); + } + } + } + + Node::ForeignItem(foreign_item) => match foreign_item.kind { + ForeignItemKind::Fn(..) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs) + } + ForeignItemKind::Static(ref t, _) => icx.to_ty(t), + ForeignItemKind::Type => tcx.mk_foreign(def_id), + }, + + Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def { + VariantData::Unit(..) | VariantData::Struct(..) => { + tcx.type_of(tcx.hir().get_parent_did(hir_id)) + } + VariantData::Tuple(..) => { + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_fn_def(def_id, substs) + } + }, + + Node::Field(field) => icx.to_ty(&field.ty), + + Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => { + if gen.is_some() { + return tcx.typeck_tables_of(def_id).node_type(hir_id); + } + + let substs = InternalSubsts::identity_for_item(tcx, def_id); + tcx.mk_closure(def_id, substs) + } + + Node::AnonConst(_) => { + let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); + match parent_node { + Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. }) + | Node::Ty(&Ty { kind: TyKind::Typeof(ref constant), .. }) + | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) + if constant.hir_id == hir_id => + { + tcx.types.usize + } + + Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { + tcx.adt_def(tcx.hir().get_parent_did(hir_id)).repr.discr_type().to_ty(tcx) + } + + Node::Ty(&Ty { kind: TyKind::Path(_), .. }) + | Node::Expr(&Expr { kind: ExprKind::Struct(..), .. }) + | Node::Expr(&Expr { kind: ExprKind::Path(_), .. }) + | Node::TraitRef(..) => { + let path = match parent_node { + Node::Ty(&Ty { + kind: TyKind::Path(QPath::Resolved(_, ref path)), .. + }) + | Node::Expr(&Expr { + kind: ExprKind::Path(QPath::Resolved(_, ref path)), + .. + }) => Some(&**path), + Node::Expr(&Expr { kind: ExprKind::Struct(ref path, ..), .. }) => { + if let QPath::Resolved(_, ref path) = **path { + Some(&**path) + } else { + None + } + } + Node::TraitRef(&TraitRef { ref path, .. }) => Some(&**path), + _ => None, + }; + + if let Some(path) = path { + let arg_index = path + .segments + .iter() + .filter_map(|seg| seg.args.as_ref()) + .map(|generic_args| generic_args.args) + .find_map(|args| { + args.iter() + .filter(|arg| arg.is_const()) + .enumerate() + .filter(|(_, arg)| arg.id() == hir_id) + .map(|(index, _)| index) + .next() + }) + .unwrap_or_else(|| { + bug!("no arg matching AnonConst in path"); + }); + + // We've encountered an `AnonConst` in some path, so we need to + // figure out which generic parameter it corresponds to and return + // the relevant type. + let generics = match path.res { + Res::Def(DefKind::Ctor(..), def_id) => { + tcx.generics_of(tcx.parent(def_id).unwrap()) + } + Res::Def(_, def_id) => tcx.generics_of(def_id), + Res::Err => return tcx.types.err, + res => { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!("unexpected const parent path def {:?}", res,), + ); + return tcx.types.err; + } + }; + + generics + .params + .iter() + .filter(|param| { + if let ty::GenericParamDefKind::Const = param.kind { + true + } else { + false + } + }) + .nth(arg_index) + .map(|param| tcx.type_of(param.def_id)) + // This is no generic parameter associated with the arg. This is + // probably from an extra arg where one is not needed. + .unwrap_or(tcx.types.err) + } else { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!("unexpected const parent path {:?}", parent_node,), + ); + return tcx.types.err; + } + } + + x => { + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!("unexpected const parent in type_of_def_id(): {:?}", x), + ); + tcx.types.err + } + } + } + + Node::GenericParam(param) => match ¶m.kind { + GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty), + GenericParamKind::Const { ty: ref hir_ty, .. } => { + let ty = icx.to_ty(hir_ty); + if !tcx.features().const_compare_raw_pointers { + let err = match ty.peel_refs().kind { + ty::FnPtr(_) => Some("function pointers"), + ty::RawPtr(_) => Some("raw pointers"), + _ => None, + }; + if let Some(unsupported_type) = err { + feature_err( + &tcx.sess.parse_sess, + sym::const_compare_raw_pointers, + hir_ty.span, + &format!( + "using {} as const generic parameters is unstable", + unsupported_type + ), + ) + .emit(); + }; + } + if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty) + .is_some() + { + struct_span_err!( + tcx.sess, + hir_ty.span, + E0741, + "the types of const generic parameters must derive `PartialEq` and `Eq`", + ) + .span_label( + hir_ty.span, + format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty), + ) + .emit(); + } + ty + } + x => bug!("unexpected non-type Node::GenericParam: {:?}", x), + }, + + x => { + bug!("unexpected sort of node in type_of_def_id(): {:?}", x); + } + } +} + +fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { + use rustc_hir::{Expr, ImplItem, Item, TraitItem}; + + debug!("find_opaque_ty_constraints({:?})", def_id); + + struct ConstraintLocator<'tcx> { + tcx: TyCtxt<'tcx>, + def_id: DefId, + // (first found type span, actual type, mapping from the opaque type's generic + // parameters to the concrete type's generic parameters) + // + // The mapping is an index for each use site of a generic parameter in the concrete type + // + // The indices index into the generic parameters on the opaque type. + found: Option<(Span, Ty<'tcx>, Vec)>, + } + + impl ConstraintLocator<'_> { + fn check(&mut self, def_id: DefId) { + // Don't try to check items that cannot possibly constrain the type. + if !self.tcx.has_typeck_tables(def_id) { + debug!( + "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`: no tables", + self.def_id, def_id, + ); + return; + } + // Calling `mir_borrowck` can lead to cycle errors through + // const-checking, avoid calling it if we don't have to. + if !self.tcx.typeck_tables_of(def_id).concrete_opaque_types.contains_key(&self.def_id) { + debug!( + "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`", + self.def_id, def_id, + ); + return; + } + // Use borrowck to get the type with unerased regions. + let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id); + if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty { + debug!( + "find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}", + self.def_id, def_id, ty, + ); + + // FIXME(oli-obk): trace the actual span from inference to improve errors. + let span = self.tcx.def_span(def_id); + // used to quickly look up the position of a generic parameter + let mut index_map: FxHashMap = FxHashMap::default(); + // Skipping binder is ok, since we only use this to find generic parameters and + // their positions. + for (idx, subst) in substs.iter().enumerate() { + if let GenericArgKind::Type(ty) = subst.unpack() { + if let ty::Param(p) = ty.kind { + if index_map.insert(p, idx).is_some() { + // There was already an entry for `p`, meaning a generic parameter + // was used twice. + self.tcx.sess.span_err( + span, + &format!( + "defining opaque type use restricts opaque \ + type by using the generic parameter `{}` twice", + p, + ), + ); + return; + } + } else { + self.tcx.sess.delay_span_bug( + span, + &format!( + "non-defining opaque ty use in defining scope: {:?}, {:?}", + concrete_type, substs, + ), + ); + } + } + } + // Compute the index within the opaque type for each generic parameter used in + // the concrete type. + let indices = concrete_type + .subst(self.tcx, substs) + .walk() + .filter_map(|t| match &t.kind { + ty::Param(p) => Some(*index_map.get(p).unwrap()), + _ => None, + }) + .collect(); + let is_param = |ty: Ty<'_>| match ty.kind { + ty::Param(_) => true, + _ => false, + }; + let bad_substs: Vec<_> = substs + .iter() + .enumerate() + .filter_map(|(i, k)| { + if let GenericArgKind::Type(ty) = k.unpack() { Some((i, ty)) } else { None } + }) + .filter(|(_, ty)| !is_param(ty)) + .collect(); + if !bad_substs.is_empty() { + let identity_substs = InternalSubsts::identity_for_item(self.tcx, self.def_id); + for (i, bad_subst) in bad_substs { + self.tcx.sess.span_err( + span, + &format!( + "defining opaque type use does not fully define opaque type: \ + generic parameter `{}` is specified as concrete type `{}`", + identity_substs.type_at(i), + bad_subst + ), + ); + } + } else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found { + let mut ty = concrete_type.walk().fuse(); + let mut p_ty = prev_ty.walk().fuse(); + let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.kind, &p.kind) { + // Type parameters are equal to any other type parameter for the purpose of + // concrete type equality, as it is possible to obtain the same type just + // by passing matching parameters to a function. + (ty::Param(_), ty::Param(_)) => true, + _ => t == p, + }); + if !iter_eq || ty.next().is_some() || p_ty.next().is_some() { + debug!("find_opaque_ty_constraints: span={:?}", span); + // Found different concrete types for the opaque type. + let mut err = self.tcx.sess.struct_span_err( + span, + "concrete type differs from previous defining opaque type use", + ); + err.span_label( + span, + format!("expected `{}`, got `{}`", prev_ty, concrete_type), + ); + err.span_note(prev_span, "previous use here"); + err.emit(); + } else if indices != *prev_indices { + // Found "same" concrete types, but the generic parameter order differs. + let mut err = self.tcx.sess.struct_span_err( + span, + "concrete type's generic parameters differ from previous defining use", + ); + use std::fmt::Write; + let mut s = String::new(); + write!(s, "expected [").unwrap(); + let list = |s: &mut String, indices: &Vec| { + let mut indices = indices.iter().cloned(); + if let Some(first) = indices.next() { + write!(s, "`{}`", substs[first]).unwrap(); + for i in indices { + write!(s, ", `{}`", substs[i]).unwrap(); + } + } + }; + list(&mut s, prev_indices); + write!(s, "], got [").unwrap(); + list(&mut s, &indices); + write!(s, "]").unwrap(); + err.span_label(span, s); + err.span_note(prev_span, "previous use here"); + err.emit(); + } + } else { + self.found = Some((span, concrete_type, indices)); + } + } else { + debug!( + "find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`", + self.def_id, def_id, + ); + } + } + } + + impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::All(self.tcx.hir()) + } + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + if let hir::ExprKind::Closure(..) = ex.kind { + let def_id = self.tcx.hir().local_def_id(ex.hir_id); + self.check(def_id); + } + intravisit::walk_expr(self, ex); + } + fn visit_item(&mut self, it: &'tcx Item<'tcx>) { + debug!("find_existential_constraints: visiting {:?}", it); + let def_id = self.tcx.hir().local_def_id(it.hir_id); + // The opaque type itself or its children are not within its reveal scope. + if def_id != self.def_id { + self.check(def_id); + intravisit::walk_item(self, it); + } + } + fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { + debug!("find_existential_constraints: visiting {:?}", it); + let def_id = self.tcx.hir().local_def_id(it.hir_id); + // The opaque type itself or its children are not within its reveal scope. + if def_id != self.def_id { + self.check(def_id); + intravisit::walk_impl_item(self, it); + } + } + fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { + debug!("find_existential_constraints: visiting {:?}", it); + let def_id = self.tcx.hir().local_def_id(it.hir_id); + self.check(def_id); + intravisit::walk_trait_item(self, it); + } + } + + let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let scope = tcx.hir().get_defining_scope(hir_id); + let mut locator = ConstraintLocator { def_id, tcx, found: None }; + + debug!("find_opaque_ty_constraints: scope={:?}", scope); + + if scope == hir::CRATE_HIR_ID { + intravisit::walk_crate(&mut locator, tcx.hir().krate()); + } else { + debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope)); + match tcx.hir().get(scope) { + // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods + // This allows our visitor to process the defining item itself, causing + // it to pick up any 'sibling' defining uses. + // + // For example, this code: + // ``` + // fn foo() { + // type Blah = impl Debug; + // let my_closure = || -> Blah { true }; + // } + // ``` + // + // requires us to explicitly process `foo()` in order + // to notice the defining usage of `Blah`. + Node::Item(ref it) => locator.visit_item(it), + Node::ImplItem(ref it) => locator.visit_impl_item(it), + Node::TraitItem(ref it) => locator.visit_trait_item(it), + other => bug!("{:?} is not a valid scope for an opaque type item", other), + } + } + + match locator.found { + Some((_, ty, _)) => ty, + None => { + let span = tcx.def_span(def_id); + tcx.sess.span_err(span, "could not find defining uses"); + tcx.types.err + } + } +} + +fn infer_placeholder_type( + tcx: TyCtxt<'_>, + def_id: DefId, + body_id: hir::BodyId, + span: Span, + item_ident: Ident, +) -> Ty<'_> { + let ty = tcx.diagnostic_only_typeck_tables_of(def_id).node_type(body_id.hir_id); + + // If this came from a free `const` or `static mut?` item, + // then the user may have written e.g. `const A = 42;`. + // In this case, the parser has stashed a diagnostic for + // us to improve in typeck so we do that now. + match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) { + Some(mut err) => { + // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. + // We are typeck and have the real type, so remove that and suggest the actual type. + err.suggestions.clear(); + err.span_suggestion( + span, + "provide a type for the item", + format!("{}: {}", item_ident, ty), + Applicability::MachineApplicable, + ) + .emit(); + } + None => { + let mut diag = bad_placeholder_type(tcx, vec![span]); + if ty != tcx.types.err { + diag.span_suggestion( + span, + "replace `_` with the correct type", + ty.to_string(), + Applicability::MaybeIncorrect, + ); + } + diag.emit(); + } + } + + ty +} + +fn report_assoc_ty_on_inherent_impl(tcx: TyCtxt<'_>, span: Span) { + struct_span_err!( + tcx.sess, + span, + E0202, + "associated types are not yet supported in inherent impls (see #8995)" + ) + .emit(); +} diff --git a/src/librustc_typeck/constrained_generic_params.rs b/src/librustc_typeck/constrained_generic_params.rs index 9b187d461cd..b16aa6ff3b2 100644 --- a/src/librustc_typeck/constrained_generic_params.rs +++ b/src/librustc_typeck/constrained_generic_params.rs @@ -36,7 +36,7 @@ pub fn parameters_for_impl<'tcx>( vec.into_iter().collect() } -/// If `include_projections` is false, returns the list of parameters that are +/// If `include_nonconstraining` is false, returns the list of parameters that are /// constrained by `t` - i.e., the value of each parameter in the list is /// uniquely determined by `t` (see RFC 447). If it is true, return the list /// of parameters whose values are needed in order to constrain `ty` - these @@ -79,10 +79,18 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { } fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { - if let ty::ConstKind::Param(data) = c.val { - self.parameters.push(Parameter::from(data)); + match c.val { + ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => { + // Constant expressions are not injective + return c.ty.visit_with(self); + } + ty::ConstKind::Param(data) => { + self.parameters.push(Parameter::from(data)); + } + _ => {} } - false + + c.super_visit_with(self) } } diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs index 1d3ace933cc..a45d8ce6823 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/src/librustc_typeck/expr_use_visitor.rs @@ -7,12 +7,12 @@ pub use self::ConsumeMode::*; // Export these here so that Clippy can use them. pub use mc::{Place, PlaceBase, Projection}; -use rustc::infer::InferCtxt; use rustc::ty::{self, adjustment, TyCtxt}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::PatKind; +use rustc_infer::infer::InferCtxt; use crate::mem_categorization as mc; use rustc_span::Span; @@ -519,7 +519,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { for &var_id in upvars.keys() { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_id }, - closure_expr_id: closure_def_id.to_local(), + closure_expr_id: closure_def_id.expect_local(), }; let upvar_capture = self.mc.tables.upvar_capture(upvar_id); let captured_place = return_if_err!(self.cat_captured_var( diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs index e9c18b59da9..42cb4fcf85d 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/src/librustc_typeck/impl_wf_check.rs @@ -9,6 +9,8 @@ //! fixed, but for the moment it's easier to do these checks early. use crate::constrained_generic_params as cgp; +use min_specialization::check_min_specialization; + use rustc::ty::query::Providers; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -16,9 +18,11 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_span::Span; + use std::collections::hash_map::Entry::{Occupied, Vacant}; -use rustc_span::Span; +mod min_specialization; /// Checks that all the type/lifetime parameters on an impl also /// appear in the trait ref or self type (or are constrained by a @@ -60,7 +64,9 @@ pub fn impl_wf_check(tcx: TyCtxt<'_>) { } fn check_mod_impl_wf(tcx: TyCtxt<'_>, module_def_id: DefId) { - tcx.hir().visit_item_likes_in_module(module_def_id, &mut ImplWfCheck { tcx }); + let min_specialization = tcx.features().min_specialization; + tcx.hir() + .visit_item_likes_in_module(module_def_id, &mut ImplWfCheck { tcx, min_specialization }); } pub fn provide(providers: &mut Providers<'_>) { @@ -69,6 +75,7 @@ pub fn provide(providers: &mut Providers<'_>) { struct ImplWfCheck<'tcx> { tcx: TyCtxt<'tcx>, + min_specialization: bool, } impl ItemLikeVisitor<'tcx> for ImplWfCheck<'tcx> { @@ -77,6 +84,9 @@ impl ItemLikeVisitor<'tcx> for ImplWfCheck<'tcx> { let impl_def_id = self.tcx.hir().local_def_id(item.hir_id); enforce_impl_params_are_constrained(self.tcx, impl_def_id, items); enforce_impl_items_are_distinct(self.tcx, items); + if self.min_specialization { + check_min_specialization(self.tcx, impl_def_id, item.span); + } } } @@ -120,11 +130,26 @@ fn enforce_impl_params_are_constrained( let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs .iter() .map(|item_ref| tcx.hir().local_def_id(item_ref.id.hir_id)) - .filter(|&def_id| { + .flat_map(|def_id| { let item = tcx.associated_item(def_id); - item.kind == ty::AssocKind::Type && item.defaultness.has_value() + match item.kind { + ty::AssocKind::Type => { + if item.defaultness.has_value() { + cgp::parameters_for(&tcx.type_of(def_id), true) + } else { + Vec::new() + } + } + ty::AssocKind::OpaqueTy => { + // We don't know which lifetimes appear in the actual + // opaque type, so use all of the lifetimes that appear + // in the type's predicates. + let predicates = tcx.predicates_of(def_id).instantiate_identity(tcx); + cgp::parameters_for(&predicates, true) + } + ty::AssocKind::Method | ty::AssocKind::Const => Vec::new(), + } }) - .flat_map(|def_id| cgp::parameters_for(&tcx.type_of(def_id), true)) .collect(); for param in &impl_generics.params { @@ -212,7 +237,7 @@ fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_item_refs: &[hir::ImplI hir::ImplItemKind::TyAlias(_) => &mut seen_type_items, _ => &mut seen_value_items, }; - match seen_items.entry(impl_item.ident.modern()) { + match seen_items.entry(impl_item.ident.normalize_to_macros_2_0()) { Occupied(entry) => { let mut err = struct_span_err!( tcx.sess, diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs new file mode 100644 index 00000000000..cae88376118 --- /dev/null +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -0,0 +1,409 @@ +//! # Minimal Specialization +//! +//! This module contains the checks for sound specialization used when the +//! `min_specialization` feature is enabled. This requires that the impl is +//! *always applicable*. +//! +//! If `impl1` specializes `impl2` then `impl1` is always applicable if we know +//! that all the bounds of `impl2` are satisfied, and all of the bounds of +//! `impl1` are satisfied for some choice of lifetimes then we know that +//! `impl1` applies for any choice of lifetimes. +//! +//! ## Basic approach +//! +//! To enforce this requirement on specializations we take the following +//! approach: +//! +//! 1. Match up the substs for `impl2` so that the implemented trait and +//! self-type match those for `impl1`. +//! 2. Check for any direct use of `'static` in the substs of `impl2`. +//! 3. Check that all of the generic parameters of `impl1` occur at most once +//! in the *unconstrained* substs for `impl2`. A parameter is constrained if +//! its value is completely determined by an associated type projection +//! predicate. +//! 4. Check that all predicates on `impl1` either exist on `impl2` (after +//! matching substs), or are well-formed predicates for the trait's type +//! arguments. +//! +//! ## Example +//! +//! Suppose we have the following always applicable impl: +//! +//! ```rust +//! impl SpecExtend for std::vec::IntoIter { /* specialized impl */ } +//! impl> SpecExtend for I { /* default impl */ } +//! ``` +//! +//! We get that the subst for `impl2` are `[T, std::vec::IntoIter]`. `T` is +//! constrained to be `::Item`, so we check only +//! `std::vec::IntoIter` for repeated parameters, which it doesn't have. The +//! predicates of `impl1` are only `T: Sized`, which is also a predicate of +//! `impl2`. So this specialization is sound. +//! +//! ## Extensions +//! +//! Unfortunately not all specializations in the standard library are allowed +//! by this. So there are two extensions to these rules that allow specializing +//! on some traits: that is, using them as bounds on the specializing impl, +//! even when they don't occur in the base impl. +//! +//! ### rustc_specialization_trait +//! +//! If a trait is always applicable, then it's sound to specialize on it. We +//! check trait is always applicable in the same way as impls, except that step +//! 4 is now "all predicates on `impl1` are always applicable". We require that +//! `specialization` or `min_specialization` is enabled to implement these +//! traits. +//! +//! ### rustc_unsafe_specialization_marker +//! +//! There are also some specialization on traits with no methods, including the +//! stable `FusedIterator` trait. We allow marking marker traits with an +//! unstable attribute that means we ignore them in point 3 of the checks +//! above. This is unsound, in the sense that the specialized impl may be used +//! when it doesn't apply, but we allow it in the short term since it can't +//! cause use after frees with purely safe code in the same way as specializing +//! on traits with methods can. + +use crate::constrained_generic_params as cgp; + +use rustc::middle::region::ScopeTree; +use rustc::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; +use rustc::ty::trait_def::TraitSpecializationKind; +use rustc::ty::{self, InstantiatedPredicates, TyCtxt, TypeFoldable}; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; +use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt}; +use rustc_infer::traits::specialization_graph::Node; +use rustc_span::Span; +use rustc_trait_selection::traits::{self, translate_substs, wf}; + +pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: DefId, span: Span) { + if let Some(node) = parent_specialization_node(tcx, impl_def_id) { + tcx.infer_ctxt().enter(|infcx| { + check_always_applicable(&infcx, impl_def_id, node, span); + }); + } +} + +fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: DefId) -> Option { + let trait_ref = tcx.impl_trait_ref(impl1_def_id)?; + let trait_def = tcx.trait_def(trait_ref.def_id); + + let impl2_node = trait_def.ancestors(tcx, impl1_def_id).ok()?.nth(1)?; + + let always_applicable_trait = + matches!(trait_def.specialization_kind, TraitSpecializationKind::AlwaysApplicable); + if impl2_node.is_from_trait() && !always_applicable_trait { + // Implementing a normal trait isn't a specialization. + return None; + } + Some(impl2_node) +} + +/// Check that `impl1` is a sound specialization +fn check_always_applicable( + infcx: &InferCtxt<'_, '_>, + impl1_def_id: DefId, + impl2_node: Node, + span: Span, +) { + if let Some((impl1_substs, impl2_substs)) = + get_impl_substs(infcx, impl1_def_id, impl2_node, span) + { + let impl2_def_id = impl2_node.def_id(); + debug!( + "check_always_applicable(\nimpl1_def_id={:?},\nimpl2_def_id={:?},\nimpl2_substs={:?}\n)", + impl1_def_id, impl2_def_id, impl2_substs + ); + + let tcx = infcx.tcx; + + let parent_substs = if impl2_node.is_from_trait() { + impl2_substs.to_vec() + } else { + unconstrained_parent_impl_substs(tcx, impl2_def_id, impl2_substs) + }; + + check_static_lifetimes(tcx, &parent_substs, span); + check_duplicate_params(tcx, impl1_substs, &parent_substs, span); + + check_predicates(infcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span); + } +} + +/// Given a specializing impl `impl1`, and the base impl `impl2`, returns two +/// substitutions `(S1, S2)` that equate their trait references. The returned +/// types are expressed in terms of the generics of `impl1`. +/// +/// Example +/// +/// impl Foo for B { /* impl2 */ } +/// impl Foo> for C { /* impl1 */ } +/// +/// Would return `S1 = [C]` and `S2 = [Vec, C]`. +fn get_impl_substs<'tcx>( + infcx: &InferCtxt<'_, 'tcx>, + impl1_def_id: DefId, + impl2_node: Node, + span: Span, +) -> Option<(SubstsRef<'tcx>, SubstsRef<'tcx>)> { + let tcx = infcx.tcx; + let param_env = tcx.param_env(impl1_def_id); + + let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id); + let impl2_substs = translate_substs(infcx, param_env, impl1_def_id, impl1_substs, impl2_node); + + // Conservatively use an empty `ParamEnv`. + let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty()); + infcx.resolve_regions_and_report_errors( + impl1_def_id, + &ScopeTree::default(), + &outlives_env, + RegionckMode::default(), + ); + let impl2_substs = match infcx.fully_resolve(&impl2_substs) { + Ok(s) => s, + Err(_) => { + tcx.sess.struct_span_err(span, "could not resolve substs on overridden impl").emit(); + return None; + } + }; + Some((impl1_substs, impl2_substs)) +} + +/// Returns a list of all of the unconstrained subst of the given impl. +/// +/// For example given the impl: +/// +/// impl<'a, T, I> ... where &'a I: IntoIterator +/// +/// This would return the substs corresponding to `['a, I]`, because knowing +/// `'a` and `I` determines the value of `T`. +fn unconstrained_parent_impl_substs<'tcx>( + tcx: TyCtxt<'tcx>, + impl_def_id: DefId, + impl_substs: SubstsRef<'tcx>, +) -> Vec> { + let impl_generic_predicates = tcx.predicates_of(impl_def_id); + let mut unconstrained_parameters = FxHashSet::default(); + let mut constrained_params = FxHashSet::default(); + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); + + // Unfortunately the functions in `constrained_generic_parameters` don't do + // what we want here. We want only a list of constrained parameters while + // the functions in `cgp` add the constrained parameters to a list of + // unconstrained parameters. + for (predicate, _) in impl_generic_predicates.predicates.iter() { + if let ty::Predicate::Projection(proj) = predicate { + let projection_ty = proj.skip_binder().projection_ty; + let projected_ty = proj.skip_binder().ty; + + let unbound_trait_ref = projection_ty.trait_ref(tcx); + if Some(unbound_trait_ref) == impl_trait_ref { + continue; + } + + unconstrained_parameters.extend(cgp::parameters_for(&projection_ty, true)); + + for param in cgp::parameters_for(&projected_ty, false) { + if !unconstrained_parameters.contains(¶m) { + constrained_params.insert(param.0); + } + } + + unconstrained_parameters.extend(cgp::parameters_for(&projected_ty, true)); + } + } + + impl_substs + .iter() + .enumerate() + .filter(|&(idx, _)| !constrained_params.contains(&(idx as u32))) + .map(|(_, arg)| *arg) + .collect() +} + +/// Check that parameters of the derived impl don't occur more than once in the +/// equated substs of the base impl. +/// +/// For example forbid the following: +/// +/// impl Tr for A { } +/// impl Tr for (B, B) { } +/// +/// Note that only consider the unconstrained parameters of the base impl: +/// +/// impl> Tr for I { } +/// impl Tr for Vec { } +/// +/// The substs for the parent impl here are `[T, Vec]`, which repeats `T`, +/// but `S` is constrained in the parent impl, so `parent_substs` is only +/// `[Vec]`. This means we allow this impl. +fn check_duplicate_params<'tcx>( + tcx: TyCtxt<'tcx>, + impl1_substs: SubstsRef<'tcx>, + parent_substs: &Vec>, + span: Span, +) { + let mut base_params = cgp::parameters_for(parent_substs, true); + base_params.sort_by_key(|param| param.0); + if let (_, [duplicate, ..]) = base_params.partition_dedup() { + let param = impl1_substs[duplicate.0 as usize]; + tcx.sess + .struct_span_err(span, &format!("specializing impl repeats parameter `{}`", param)) + .emit(); + } +} + +/// Check that `'static` lifetimes are not introduced by the specializing impl. +/// +/// For example forbid the following: +/// +/// impl Tr for A { } +/// impl Tr for &'static i32 { } +fn check_static_lifetimes<'tcx>( + tcx: TyCtxt<'tcx>, + parent_substs: &Vec>, + span: Span, +) { + if tcx.any_free_region_meets(parent_substs, |r| *r == ty::ReStatic) { + tcx.sess.struct_span_err(span, &format!("cannot specialize on `'static` lifetime")).emit(); + } +} + +/// Check whether predicates on the specializing impl (`impl1`) are allowed. +/// +/// Each predicate `P` must be: +/// +/// * global (not reference any parameters) +/// * `T: Tr` predicate where `Tr` is an always-applicable trait +/// * on the base `impl impl2` +/// * Currently this check is done using syntactic equality, which is +/// conservative but generally sufficient. +/// * a well-formed predicate of a type argument of the trait being implemented, +/// including the `Self`-type. +fn check_predicates<'tcx>( + infcx: &InferCtxt<'_, 'tcx>, + impl1_def_id: DefId, + impl1_substs: SubstsRef<'tcx>, + impl2_node: Node, + impl2_substs: SubstsRef<'tcx>, + span: Span, +) { + let tcx = infcx.tcx; + let impl1_predicates = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs); + let mut impl2_predicates = if impl2_node.is_from_trait() { + // Always applicable traits have to be always applicable without any + // assumptions. + InstantiatedPredicates::empty() + } else { + tcx.predicates_of(impl2_node.def_id()).instantiate(tcx, impl2_substs) + }; + debug!( + "check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)", + impl1_predicates, impl2_predicates, + ); + + // Since impls of always applicable traits don't get to assume anything, we + // can also assume their supertraits apply. + // + // For example, we allow: + // + // #[rustc_specialization_trait] + // trait AlwaysApplicable: Debug { } + // + // impl Tr for T { } + // impl Tr for T { } + // + // Specializing on `AlwaysApplicable` allows also specializing on `Debug` + // which is sound because we forbid impls like the following + // + // impl AlwaysApplicable for D { } + let always_applicable_traits: Vec<_> = impl1_predicates + .predicates + .iter() + .filter(|predicate| { + matches!( + trait_predicate_kind(tcx, predicate), + Some(TraitSpecializationKind::AlwaysApplicable) + ) + }) + .copied() + .collect(); + + // Include the well-formed predicates of the type parameters of the impl. + for ty in tcx.impl_trait_ref(impl1_def_id).unwrap().substs.types() { + if let Some(obligations) = wf::obligations( + infcx, + tcx.param_env(impl1_def_id), + tcx.hir().as_local_hir_id(impl1_def_id).unwrap(), + ty, + span, + ) { + impl2_predicates + .predicates + .extend(obligations.into_iter().map(|obligation| obligation.predicate)) + } + } + impl2_predicates.predicates.extend(traits::elaborate_predicates(tcx, always_applicable_traits)); + + for predicate in impl1_predicates.predicates { + if !impl2_predicates.predicates.contains(&predicate) { + check_specialization_on(tcx, &predicate, span) + } + } +} + +fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: &ty::Predicate<'tcx>, span: Span) { + debug!("can_specialize_on(predicate = {:?})", predicate); + match predicate { + // Global predicates are either always true or always false, so we + // are fine to specialize on. + _ if predicate.is_global() => (), + // We allow specializing on explicitly marked traits with no associated + // items. + ty::Predicate::Trait(pred, hir::Constness::NotConst) => { + if !matches!( + trait_predicate_kind(tcx, predicate), + Some(TraitSpecializationKind::Marker) + ) { + tcx.sess + .struct_span_err( + span, + &format!( + "cannot specialize on trait `{}`", + tcx.def_path_str(pred.def_id()), + ), + ) + .emit() + } + } + _ => tcx + .sess + .struct_span_err(span, &format!("cannot specialize on `{:?}`", predicate)) + .emit(), + } +} + +fn trait_predicate_kind<'tcx>( + tcx: TyCtxt<'tcx>, + predicate: &ty::Predicate<'tcx>, +) -> Option { + match predicate { + ty::Predicate::Trait(pred, hir::Constness::NotConst) => { + Some(tcx.trait_def(pred.def_id()).specialization_kind) + } + ty::Predicate::Trait(_, hir::Constness::Const) + | ty::Predicate::RegionOutlives(_) + | ty::Predicate::TypeOutlives(_) + | ty::Predicate::Projection(_) + | ty::Predicate::WellFormed(_) + | ty::Predicate::Subtype(_) + | ty::Predicate::ObjectSafe(_) + | ty::Predicate::ClosureKind(..) + | ty::Predicate::ConstEvaluatable(..) => None, + } +} diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 067b33c1447..e487e0d265c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -64,6 +64,7 @@ This API is completely unstable and subject to change. #![feature(nll)] #![feature(try_blocks)] #![feature(never_type)] +#![feature(slice_partition_dedup)] #![recursion_limit = "256"] #[macro_use] @@ -83,17 +84,11 @@ mod collect; mod constrained_generic_params; mod impl_wf_check; mod mem_categorization; -mod namespace; mod outlives; mod structured_errors; mod variance; -use rustc::infer::InferOk; -use rustc::lint; use rustc::middle; -use rustc::session; -use rustc::session::config::EntryFnType; -use rustc::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt}; use rustc::ty::query::Providers; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt}; @@ -103,8 +98,15 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::Node; +use rustc_infer::infer::{InferOk, TyCtxtInferExt}; +use rustc_infer::traits::TraitEngineExt as _; +use rustc_session::config::EntryFnType; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::{ + ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _, +}; use std::iter; diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs index d3d0aa2e580..7d8bf71cf97 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/src/librustc_typeck/mem_categorization.rs @@ -48,16 +48,18 @@ //! result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference //! tied to `x`. The type of `x'` will be a borrowed pointer. -use rustc::infer::InferCtxt; use rustc::ty::adjustment; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, Ty, TyCtxt}; + use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::PatKind; +use rustc_infer::infer::InferCtxt; use rustc_span::Span; +use rustc_trait_selection::infer::InferCtxtExt; #[derive(Clone, Debug)] pub enum PlaceBase { @@ -424,7 +426,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | Res::Def(DefKind::ConstParam, _) | Res::Def(DefKind::AssocConst, _) | Res::Def(DefKind::Fn, _) - | Res::Def(DefKind::Method, _) + | Res::Def(DefKind::AssocFn, _) | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)), Res::Def(DefKind::Static, _) => Ok(Place { @@ -468,7 +470,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_id }, - closure_expr_id: closure_expr_def_id.to_local(), + closure_expr_id: closure_expr_def_id.expect_local(), }; let var_ty = self.node_ty(var_id)?; diff --git a/src/librustc_typeck/namespace.rs b/src/librustc_typeck/namespace.rs deleted file mode 100644 index 2aa97aa7e6f..00000000000 --- a/src/librustc_typeck/namespace.rs +++ /dev/null @@ -1,27 +0,0 @@ -use rustc::ty; -use rustc_hir as hir; - -// Whether an item exists in the type or value namespace. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum Namespace { - Type, - Value, -} - -impl From for Namespace { - fn from(a_kind: ty::AssocKind) -> Self { - match a_kind { - ty::AssocKind::OpaqueTy | ty::AssocKind::Type => Namespace::Type, - ty::AssocKind::Const | ty::AssocKind::Method => Namespace::Value, - } - } -} - -impl<'a> From<&'a hir::ImplItemKind<'_>> for Namespace { - fn from(impl_kind: &'a hir::ImplItemKind<'_>) -> Self { - match *impl_kind { - hir::ImplItemKind::OpaqueTy(..) | hir::ImplItemKind::TyAlias(..) => Namespace::Type, - hir::ImplItemKind::Const(..) | hir::ImplItemKind::Method(..) => Namespace::Value, - } - } -} diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs index 1645f01a4b1..44473fee643 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/src/librustc_typeck/outlives/implicit_infer.rs @@ -31,10 +31,10 @@ pub fn infer_predicates<'tcx>( predicates_added = false; let mut visitor = InferVisitor { - tcx: tcx, + tcx, global_inferred_outlives: &mut global_inferred_outlives, predicates_added: &mut predicates_added, - explicit_map: explicit_map, + explicit_map, }; // Visit all the crates and infer predicates @@ -312,6 +312,6 @@ pub fn check_explicit_predicates<'tcx>( let predicate = outlives_predicate.subst(tcx, substs); debug!("predicate = {:?}", &predicate); - insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, span, required_predicates); + insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates); } } diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index 51987391097..f7b6e0fce5a 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -25,7 +25,7 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => { let crate_map = tcx.inferred_outlives_crate(LOCAL_CRATE); - let predicates = crate_map.predicates.get(&item_def_id).map(|p| *p).unwrap_or(&[]); + let predicates = crate_map.predicates.get(&item_def_id).copied().unwrap_or(&[]); if tcx.has_attr(item_def_id, sym::rustc_outlives) { let mut pred: Vec = predicates diff --git a/src/librustc_typeck/structured_errors.rs b/src/librustc_typeck/structured_errors.rs index 99b7b2001a9..a4f8472ae28 100644 --- a/src/librustc_typeck/structured_errors.rs +++ b/src/librustc_typeck/structured_errors.rs @@ -1,6 +1,6 @@ -use rustc::session::Session; use rustc::ty::{Ty, TypeFoldable}; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_session::Session; use rustc_span::Span; pub trait StructuredDiagnostic<'tcx> { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 6f5caea250b..54f84272ae8 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -105,13 +105,13 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) { - if let hir::TraitItemKind::Method(..) = trait_item.kind { + if let hir::TraitItemKind::Fn(..) = trait_item.kind { self.visit_node_helper(trait_item.hir_id); } } fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) { - if let hir::ImplItemKind::Method(..) = impl_item.kind { + if let hir::ImplItemKind::Fn(..) = impl_item.kind { self.visit_node_helper(impl_item.hir_id); } } diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index 32bd7e4c4c1..3cbb42bb5f3 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -1,7 +1,7 @@ -//! Module for inferring the variance of type and lifetime parameters. See the [rustc guide] +//! Module for inferring the variance of type and lifetime parameters. See the [rustc dev guide] //! chapter for more info. //! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/variance.html +//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/variance.html use hir::Node; use rustc::ty::query::Providers; @@ -54,13 +54,13 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { }, Node::TraitItem(item) => match item.kind { - hir::TraitItemKind::Method(..) => {} + hir::TraitItemKind::Fn(..) => {} _ => unsupported(), }, Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::Method(..) => {} + hir::ImplItemKind::Fn(..) => {} _ => unsupported(), }, @@ -79,5 +79,5 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[ty::Variance] { // Everything else must be inferred. let crate_map = tcx.crate_variances(LOCAL_CRATE); - crate_map.variances.get(&item_def_id).map(|p| *p).unwrap_or(&[]) + crate_map.variances.get(&item_def_id).copied().unwrap_or(&[]) } diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index dd593a6abb4..7e6ec96b379 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -77,8 +77,8 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>( // See the following for a discussion on dep-graph management. // - // - https://rust-lang.github.io/rustc-guide/query.html - // - https://rust-lang.github.io/rustc-guide/variance.html + // - https://rustc-dev-guide.rust-lang.org/query.html + // - https://rustc-dev-guide.rust-lang.org/variance.html tcx.hir().krate().visit_all_item_likes(&mut terms_cx); terms_cx @@ -164,13 +164,13 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) { - if let hir::TraitItemKind::Method(..) = trait_item.kind { + if let hir::TraitItemKind::Fn(..) = trait_item.kind { self.add_inferreds_for_item(trait_item.hir_id); } } fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) { - if let hir::ImplItemKind::Method(..) = impl_item.kind { + if let hir::ImplItemKind::Fn(..) = impl_item.kind { self.add_inferreds_for_item(impl_item.hir_id); } } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 74e46b1eae3..4af13e4cd58 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -9,7 +9,7 @@ name = "rustdoc" path = "lib.rs" [dependencies] -pulldown-cmark = { version = "0.5.3", default-features = false } +pulldown-cmark = { version = "0.7", default-features = false } minifier = "0.0.33" rayon = { version = "0.3.0", package = "rustc-rayon" } serde = { version = "1.0", features = ["derive"] } diff --git a/src/librustdoc/README.md b/src/librustdoc/README.md index e4f7bc30e3f..5a5f547068d 100644 --- a/src/librustdoc/README.md +++ b/src/librustdoc/README.md @@ -1,3 +1,3 @@ -For more information about how `librustdoc` works, see the [rustc guide]. +For more information about how `librustdoc` works, see the [rustc dev guide]. -[rustc guide]: https://rust-lang.github.io/rustc-guide/rustdoc.html +[rustc dev guide]: https://rustc-dev-guide.rust-lang.org/rustdoc.html diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 8edd0591c85..c85b21a5500 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -1,7 +1,7 @@ -use rustc::traits::auto_trait::{self, AutoTraitResult}; use rustc::ty::{self, Region, RegionVid, TypeFoldable}; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; +use rustc_trait_selection::traits::auto_trait::{self, AutoTraitResult}; use std::fmt::Debug; @@ -493,7 +493,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // Writing a projection trait bound of the form // ::Name : ?Sized // is illegal, because ?Sized bounds can only - // be written in the (here, nonexistant) definition + // be written in the (here, nonexistent) definition // of the type. // Therefore, we make sure that we never add a ?Sized // bound for projections diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 288446b6219..e66f8697717 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -1,9 +1,10 @@ -use rustc::infer::InferOk; -use rustc::traits; +use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc::ty::subst::Subst; use rustc::ty::{ToPredicate, WithConstness}; use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; +use rustc_infer::infer::{InferOk, TyCtxtInferExt}; +use rustc_infer::traits; use rustc_span::DUMMY_SP; use super::*; @@ -114,8 +115,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .cx .tcx .associated_items(impl_def_id) - .iter() - .copied() + .in_definition_order() .collect::>() .clean(self.cx), polarity: None, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index da3a277dc2a..775d600fc3d 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -7,10 +7,10 @@ use std::fmt::{self, Write}; use std::mem; use std::ops; +use rustc_ast::ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem}; use rustc_feature::Features; use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; -use syntax::ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem}; use rustc_span::Span; diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index d090bf32503..3b26742e716 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -1,10 +1,10 @@ use super::*; +use rustc_ast::ast::*; +use rustc_ast::attr; +use rustc_ast::with_default_globals; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; -use syntax::ast::*; -use syntax::attr; -use syntax::with_default_globals; fn word_cfg(s: &str) -> Cfg { Cfg::Cfg(Symbol::intern(s), None) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 90ce8802f65..153f7af9f97 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -3,6 +3,7 @@ use std::iter::once; use rustc::ty; +use rustc_ast::ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -11,9 +12,7 @@ use rustc_hir::Mutability; use rustc_metadata::creader::LoadedMacro; use rustc_mir::const_eval::is_min_const_fn; use rustc_span::hygiene::MacroKind; -use rustc_span::symbol::sym; use rustc_span::Span; -use syntax::ast; use crate::clean::{self, GetDefId, ToSource, TypeKind}; use crate::core::DocContext; @@ -42,11 +41,7 @@ pub fn try_inline( attrs: Option>, visited: &mut FxHashSet, ) -> Option> { - let did = if let Some(did) = res.opt_def_id() { - did - } else { - return None; - }; + let did = res.opt_def_id()?; if did.is_local() { return None; } @@ -190,13 +185,14 @@ pub fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKind) } pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { + let trait_items = + cx.tcx.associated_items(did).in_definition_order().map(|item| item.clean(cx)).collect(); + let auto_trait = cx.tcx.trait_def(did).has_auto_impl; - let trait_items = cx.tcx.associated_items(did).iter().map(|item| item.clean(cx)).collect(); let predicates = cx.tcx.predicates_of(did); let generics = (cx.tcx.generics_of(did), predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); - let is_spotlight = load_attrs(cx, did).clean(cx).has_doc_flag(sym::spotlight); let is_auto = cx.tcx.trait_is_auto(did); clean::Trait { auto: auto_trait, @@ -204,7 +200,6 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { generics, items: trait_items, bounds: supertrait_bounds, - is_spotlight, is_auto, } } @@ -376,7 +371,7 @@ pub fn build_impl( } else { ( tcx.associated_items(did) - .iter() + .in_definition_order() .filter_map(|item| { if associated_trait.is_some() || item.vis == ty::Visibility::Public { Some(item.clean(cx)) @@ -579,7 +574,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: name: ref _name, }, ref bounds, - } => !(*s == "Self" && did == trait_did) && !bounds.is_empty(), + } => !(bounds.is_empty() || *s == "Self" && did == trait_did), _ => true, }); g diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 87edc88611f..e69d4ddc2d0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -9,25 +9,25 @@ mod simplify; pub mod types; pub mod utils; -use rustc::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc::middle::lang_items; use rustc::middle::resolve_lifetime as rl; use rustc::middle::stability; use rustc::ty::fold::TypeFolder; use rustc::ty::subst::InternalSubsts; use rustc::ty::{self, AdtKind, Lift, Ty, TyCtxt}; +use rustc_ast::ast::{self, Ident}; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; use rustc_index::vec::{Idx, IndexVec}; +use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc_mir::const_eval::is_min_const_fn; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym}; use rustc_span::{self, Pos}; use rustc_typeck::hir_ty_to_ty; -use syntax::ast::{self, Ident}; use std::collections::hash_map::Entry; use std::default::Default; @@ -43,14 +43,14 @@ use utils::*; pub use utils::{get_auto_trait_and_blanket_impls, krate, register_res}; -pub use self::types::FunctionRetTy::*; +pub use self::types::FnRetTy::*; pub use self::types::ItemEnum::*; pub use self::types::SelfTy::*; pub use self::types::Type::*; pub use self::types::Visibility::{Inherited, Public}; pub use self::types::*; -const FN_OUTPUT_NAME: &'static str = "Output"; +const FN_OUTPUT_NAME: &str = "Output"; pub trait Clean { fn clean(&self, cx: &DocContext<'_>) -> T; @@ -141,6 +141,7 @@ impl Clean for CrateNum { cx.tcx .hir() .krate() + .item .module .item_ids .iter() @@ -194,6 +195,7 @@ impl Clean for CrateNum { cx.tcx .hir() .krate() + .item .module .item_ids .iter() @@ -263,9 +265,9 @@ impl Clean for doctree::Module<'_> { // determine if we should display the inner contents or // the outer `mod` item for the source code. let whence = { - let cm = cx.sess().source_map(); - let outer = cm.lookup_char_pos(self.where_outer.lo()); - let inner = cm.lookup_char_pos(self.where_inner.lo()); + let sm = cx.sess().source_map(); + let outer = sm.lookup_char_pos(self.where_outer.lo()); + let inner = sm.lookup_char_pos(self.where_inner.lo()); if outer.file.start_pos == inner.file.start_pos { // mod foo { ... } self.where_outer @@ -398,7 +400,7 @@ impl Clean for hir::GenericParam<'_> { fn clean(&self, _: &DocContext<'_>) -> Lifetime { match self.kind { hir::GenericParamKind::Lifetime { .. } => { - if self.bounds.len() > 0 { + if !self.bounds.is_empty() { let mut bounds = self.bounds.iter().map(|bound| match bound { hir::GenericBound::Outlives(lt) => lt, _ => panic!(), @@ -607,7 +609,7 @@ impl Clean for hir::GenericParam<'_> { fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef { let (name, kind) = match self.kind { hir::GenericParamKind::Lifetime { .. } => { - let name = if self.bounds.len() > 0 { + let name = if !self.bounds.is_empty() { let mut bounds = self.bounds.iter().map(|bound| match bound { hir::GenericBound::Outlives(lt) => lt, _ => panic!(), @@ -1001,8 +1003,8 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { } } -impl Clean for hir::FunctionRetTy<'_> { - fn clean(&self, cx: &DocContext<'_>) -> FunctionRetTy { +impl Clean for hir::FnRetTy<'_> { + fn clean(&self, cx: &DocContext<'_>) -> FnRetTy { match *self { Self::Return(ref typ) => Return(typ.clean(cx)), Self::DefaultReturn(..) => DefaultReturn, @@ -1013,7 +1015,6 @@ impl Clean for hir::FunctionRetTy<'_> { impl Clean for doctree::Trait<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let attrs = self.attrs.clean(cx); - let is_spotlight = attrs.has_doc_flag(sym::spotlight); Item { name: Some(self.name.clean(cx)), attrs, @@ -1028,7 +1029,6 @@ impl Clean for doctree::Trait<'_> { items: self.items.iter().map(|ti| ti.clean(cx)).collect(), generics: self.generics.clean(cx), bounds: self.bounds.clean(cx), - is_spotlight, is_auto: self.is_auto.clean(cx), }), } @@ -1078,16 +1078,36 @@ impl Clean for hir::PolyTraitRef<'_> { } } +impl Clean for hir::def::DefKind { + fn clean(&self, _: &DocContext<'_>) -> TypeKind { + match *self { + hir::def::DefKind::Mod => TypeKind::Module, + hir::def::DefKind::Struct => TypeKind::Struct, + hir::def::DefKind::Union => TypeKind::Union, + hir::def::DefKind::Enum => TypeKind::Enum, + hir::def::DefKind::Trait => TypeKind::Trait, + hir::def::DefKind::TyAlias => TypeKind::Typedef, + hir::def::DefKind::ForeignTy => TypeKind::Foreign, + hir::def::DefKind::TraitAlias => TypeKind::TraitAlias, + hir::def::DefKind::Fn => TypeKind::Function, + hir::def::DefKind::Const => TypeKind::Const, + hir::def::DefKind::Static => TypeKind::Static, + hir::def::DefKind::Macro(_) => TypeKind::Macro, + _ => TypeKind::Foreign, + } + } +} + impl Clean for hir::TraitItem<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let inner = match self.kind { hir::TraitItemKind::Const(ref ty, default) => { AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx, e))) } - hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => { + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { MethodItem((sig, &self.generics, body, None).clean(cx)) } - hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => { + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => { let (generics, decl) = enter_impl_trait(cx, || { (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx)) }); @@ -1118,7 +1138,7 @@ impl Clean for hir::ImplItem<'_> { hir::ImplItemKind::Const(ref ty, expr) => { AssocConstItem(ty.clean(cx), Some(print_const_expr(cx, expr))) } - hir::ImplItemKind::Method(ref sig, body) => { + hir::ImplItemKind::Fn(ref sig, body) => { MethodItem((sig, &self.generics, body, Some(self.defaultness)).clean(cx)) } hir::ImplItemKind::TyAlias(ref ty) => { @@ -1332,7 +1352,9 @@ impl Clean for hir::Ty<'_> { TyKind::Array(ref ty, ref length) => { let def_id = cx.tcx.hir().local_def_id(length.hir_id); let length = match cx.tcx.const_eval_poly(def_id) { - Ok(length) => print_const(cx, length), + Ok(length) => { + print_const(cx, ty::Const::from_value(cx.tcx, length, cx.tcx.types.usize)) + } Err(_) => cx .sess() .source_map() @@ -1915,10 +1937,10 @@ impl Clean for rustc_span::Span { return Span::empty(); } - let cm = cx.sess().source_map(); - let filename = cm.span_to_filename(*self); - let lo = cm.lookup_char_pos(self.lo()); - let hi = cm.lookup_char_pos(self.hi()); + let sm = cx.sess().source_map(); + let filename = sm.span_to_filename(*self); + let lo = sm.lookup_char_pos(self.lo()); + let hi = sm.lookup_char_pos(self.hi()); Span { filename, loline: lo.line, @@ -2386,9 +2408,9 @@ impl Clean for hir::TypeBindingKind<'_> { hir::TypeBindingKind::Equality { ref ty } => { TypeBindingKind::Equality { ty: ty.clean(cx) } } - hir::TypeBindingKind::Constraint { ref bounds } => TypeBindingKind::Constraint { - bounds: bounds.into_iter().map(|b| b.clean(cx)).collect(), - }, + hir::TypeBindingKind::Constraint { ref bounds } => { + TypeBindingKind::Constraint { bounds: bounds.iter().map(|b| b.clean(cx)).collect() } + } } } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 8501fee56cf..73f2c399e56 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -11,6 +11,9 @@ use std::{slice, vec}; use rustc::middle::lang_items; use rustc::middle::stability; use rustc::ty::layout::VariantIdx; +use rustc_ast::ast::{self, AttrStyle, Ident}; +use rustc_ast::attr; +use rustc_ast::util::comments::strip_doc_comment_decoration; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::Res; @@ -22,9 +25,6 @@ use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{self, FileName}; use rustc_target::spec::abi::Abi; -use syntax::ast::{self, AttrStyle, Ident}; -use syntax::attr; -use syntax::util::comments::strip_doc_comment_decoration; use crate::clean::cfg::Cfg; use crate::clean::external_path; @@ -35,7 +35,7 @@ use crate::doctree; use crate::html::item_type::ItemType; use crate::html::render::{cache, ExternalLocation}; -use self::FunctionRetTy::*; +use self::FnRetTy::*; use self::ItemEnum::*; use self::SelfTy::*; use self::Type::*; @@ -201,7 +201,7 @@ impl Item { classes.push("deprecated"); } - if classes.len() != 0 { Some(classes.join(" ")) } else { None } + if !classes.is_empty() { Some(classes.join(" ")) } else { None } }) } @@ -421,7 +421,7 @@ pub struct Attributes { impl Attributes { /// Extracts the content from an attribute `#[doc(cfg(content))]`. pub fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { - use syntax::ast::NestedMetaItem::MetaItem; + use rustc_ast::ast::NestedMetaItem::MetaItem; if let ast::MetaItemKind::List(ref nmis) = mi.kind { if nmis.len() == 1 { @@ -565,8 +565,7 @@ impl Attributes { let inner_docs = attrs .iter() - .filter(|a| a.doc_str().is_some()) - .next() + .find(|a| a.doc_str().is_some()) .map_or(true, |a| a.style == AttrStyle::Inner); Attributes { @@ -837,8 +836,8 @@ pub struct Method { pub decl: FnDecl, pub header: hir::FnHeader, pub defaultness: Option, - pub all_types: Vec, - pub ret_types: Vec, + pub all_types: Vec<(Type, TypeKind)>, + pub ret_types: Vec<(Type, TypeKind)>, } #[derive(Clone, Debug)] @@ -846,8 +845,8 @@ pub struct TyMethod { pub header: hir::FnHeader, pub decl: FnDecl, pub generics: Generics, - pub all_types: Vec, - pub ret_types: Vec, + pub all_types: Vec<(Type, TypeKind)>, + pub ret_types: Vec<(Type, TypeKind)>, } #[derive(Clone, Debug)] @@ -855,14 +854,14 @@ pub struct Function { pub decl: FnDecl, pub generics: Generics, pub header: hir::FnHeader, - pub all_types: Vec, - pub ret_types: Vec, + pub all_types: Vec<(Type, TypeKind)>, + pub ret_types: Vec<(Type, TypeKind)>, } #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct FnDecl { pub inputs: Arguments, - pub output: FunctionRetTy, + pub output: FnRetTy, pub c_variadic: bool, pub attrs: Attributes, } @@ -881,12 +880,12 @@ impl FnDecl { /// /// This function will panic if the return type does not match the expected sugaring for async /// functions. - pub fn sugared_async_return_type(&self) -> FunctionRetTy { + pub fn sugared_async_return_type(&self) -> FnRetTy { match &self.output { - FunctionRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] { + FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] { GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => { let bindings = trait_.bindings().unwrap(); - FunctionRetTy::Return(bindings[0].ty().clone()) + FnRetTy::Return(bindings[0].ty().clone()) } _ => panic!("unexpected desugaring of async function"), }, @@ -931,12 +930,12 @@ impl Argument { } #[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub enum FunctionRetTy { +pub enum FnRetTy { Return(Type), DefaultReturn, } -impl GetDefId for FunctionRetTy { +impl GetDefId for FnRetTy { fn def_id(&self) -> Option { match *self { Return(ref ty) => ty.def_id(), @@ -952,7 +951,6 @@ pub struct Trait { pub items: Vec, pub generics: Generics, pub bounds: Vec, - pub is_spotlight: bool, pub is_auto: bool, } @@ -1044,7 +1042,7 @@ pub enum PrimitiveType { Never, } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] pub enum TypeKind { Enum, Function, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index ef357056504..b54af499187 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,7 +1,7 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ - inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FunctionRetTy, Generic, GenericArg, + inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg, GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type, TypeBinding, TypeKind, Visibility, WherePredicate, @@ -38,7 +38,7 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { } externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); - // Clean the crate, translating the entire libsyntax AST to one that is + // Clean the crate, translating the entire librustc_ast AST to one that is // understood by rustdoc. let mut module = module.clean(cx); let mut masked_crates = FxHashSet::default(); @@ -121,9 +121,7 @@ pub fn external_generic_args( let args: Vec<_> = substs .iter() .filter_map(|kind| match kind.unpack() { - GenericArgKind::Lifetime(lt) => { - lt.clean(cx).and_then(|lt| Some(GenericArg::Lifetime(lt))) - } + GenericArgKind::Lifetime(lt) => lt.clean(cx).map(|lt| GenericArg::Lifetime(lt)), GenericArgKind::Type(_) if skip_self => { skip_self = false; None @@ -186,7 +184,7 @@ pub fn get_real_types( arg: &Type, cx: &DocContext<'_>, recurse: i32, -) -> FxHashSet { +) -> FxHashSet<(Type, TypeKind)> { let arg_s = arg.print().to_string(); let mut res = FxHashSet::default(); if recurse >= 10 { @@ -211,7 +209,11 @@ pub fn get_real_types( if !adds.is_empty() { res.extend(adds); } else if !ty.is_full_generic() { - res.insert(ty); + if let Some(did) = ty.def_id() { + if let Some(kind) = cx.tcx.def_kind(did).clean(cx) { + res.insert((ty, kind)); + } + } } } } @@ -227,13 +229,21 @@ pub fn get_real_types( if !adds.is_empty() { res.extend(adds); } else if !ty.is_full_generic() { - res.insert(ty.clone()); + if let Some(did) = ty.def_id() { + if let Some(kind) = cx.tcx.def_kind(did).clean(cx) { + res.insert((ty.clone(), kind)); + } + } } } } } } else { - res.insert(arg.clone()); + if let Some(did) = arg.def_id() { + if let Some(kind) = cx.tcx.def_kind(did).clean(cx) { + res.insert((arg.clone(), kind)); + } + } if let Some(gens) = arg.generics() { for gen in gens.iter() { if gen.is_full_generic() { @@ -241,8 +251,10 @@ pub fn get_real_types( if !adds.is_empty() { res.extend(adds); } - } else { - res.insert(gen.clone()); + } else if let Some(did) = gen.def_id() { + if let Some(kind) = cx.tcx.def_kind(did).clean(cx) { + res.insert((gen.clone(), kind)); + } } } } @@ -258,7 +270,7 @@ pub fn get_all_types( generics: &Generics, decl: &FnDecl, cx: &DocContext<'_>, -) -> (Vec, Vec) { +) -> (Vec<(Type, TypeKind)>, Vec<(Type, TypeKind)>) { let mut all_types = FxHashSet::default(); for arg in decl.inputs.values.iter() { if arg.type_.is_self_type() { @@ -268,15 +280,23 @@ pub fn get_all_types( if !args.is_empty() { all_types.extend(args); } else { - all_types.insert(arg.type_.clone()); + if let Some(did) = arg.type_.def_id() { + if let Some(kind) = cx.tcx.def_kind(did).clean(cx) { + all_types.insert((arg.type_.clone(), kind)); + } + } } } let ret_types = match decl.output { - FunctionRetTy::Return(ref return_type) => { + FnRetTy::Return(ref return_type) => { let mut ret = get_real_types(generics, &return_type, cx, 0); if ret.is_empty() { - ret.insert(return_type.clone()); + if let Some(did) = return_type.def_id() { + if let Some(kind) = cx.tcx.def_kind(did).clean(cx) { + ret.insert((return_type.clone(), kind)); + } + } } ret.into_iter().collect() } @@ -457,7 +477,7 @@ pub fn name_from_pat(p: &hir::Pat) -> String { } } -pub fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String { +pub fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { match n.val { ty::ConstKind::Unevaluated(def_id, _, promoted) => { let mut s = if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) { @@ -487,15 +507,18 @@ pub fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String { } pub fn print_evaluated_const(cx: &DocContext<'_>, def_id: DefId) -> Option { - let value = - cx.tcx.const_eval_poly(def_id).ok().and_then(|value| match (value.val, &value.ty.kind) { - (_, ty::Ref(..)) => None, - (ty::ConstKind::Value(ConstValue::Scalar(_)), ty::Adt(_, _)) => None, - (ty::ConstKind::Value(ConstValue::Scalar(_)), _) => { - Some(print_const_with_custom_print_scalar(cx, value)) + let value = cx.tcx.const_eval_poly(def_id).ok().and_then(|val| { + let ty = cx.tcx.type_of(def_id); + match (val, &ty.kind) { + (_, &ty::Ref(..)) => None, + (ConstValue::Scalar(_), &ty::Adt(_, _)) => None, + (ConstValue::Scalar(_), _) => { + let const_ = ty::Const::from_value(cx.tcx, val, ty); + Some(print_const_with_custom_print_scalar(cx, const_)) } _ => None, - }); + } + }); value } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 33b3e800374..179c5bfacf3 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -1,17 +1,17 @@ use std::collections::BTreeMap; +use std::convert::TryFrom; use std::ffi::OsStr; use std::fmt; use std::path::PathBuf; -use rustc::lint::Level; -use rustc::session; -use rustc::session::config::{ +use rustc_session::config::{self, parse_crate_types_from_list, parse_externs, CrateType}; +use rustc_session::config::{ build_codegen_options, build_debugging_options, get_cmd_lint_options, host_triple, nightly_options, }; -use rustc::session::config::{parse_crate_types_from_list, parse_externs, CrateType}; -use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; -use rustc::session::search_paths::SearchPath; +use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; +use rustc_session::lint::Level; +use rustc_session::search_paths::SearchPath; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_target::spec::TargetTriple; @@ -24,6 +24,33 @@ use crate::opts; use crate::passes::{self, Condition, DefaultPassOption}; use crate::theme; +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum OutputFormat { + Json, + Html, +} + +impl OutputFormat { + pub fn is_json(&self) -> bool { + match self { + OutputFormat::Json => true, + _ => false, + } + } +} + +impl TryFrom<&str> for OutputFormat { + type Error = String; + + fn try_from(value: &str) -> Result { + match value { + "json" => Ok(OutputFormat::Json), + "html" => Ok(OutputFormat::Html), + _ => Err(format!("unknown output format `{}`", value)), + } + } +} + /// Configuration options for rustdoc. #[derive(Clone)] pub struct Options { @@ -115,6 +142,8 @@ pub struct Options { pub crate_version: Option, /// Collected options specific to outputting final pages. pub render_options: RenderOptions, + /// Output format rendering (used only for "show-coverage" option for the moment) + pub output_format: Option, } impl fmt::Debug for Options { @@ -269,9 +298,9 @@ impl Options { return Err(0); } - let color = session::config::parse_color(&matches); - let (json_rendered, _artifacts) = session::config::parse_json(&matches); - let error_format = session::config::parse_error_format(&matches, color, json_rendered); + let color = config::parse_color(&matches); + let (json_rendered, _artifacts) = config::parse_json(&matches); + let error_format = config::parse_error_format(&matches, color, json_rendered); let codegen_options = build_codegen_options(matches, error_format); let debugging_options = build_debugging_options(matches, error_format); @@ -425,14 +454,6 @@ impl Options { } } - match matches.opt_str("w").as_ref().map(|s| &**s) { - Some("html") | None => {} - Some(s) => { - diag.struct_err(&format!("unknown output format: {}", s)).emit(); - return Err(1); - } - } - let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s)); if let Some(ref index_page) = index_page { if !index_page.is_file() { @@ -469,6 +490,29 @@ impl Options { } }; + let output_format = match matches.opt_str("output-format") { + Some(s) => match OutputFormat::try_from(s.as_str()) { + Ok(o) => { + if o.is_json() && !show_coverage { + diag.struct_err("json output format isn't supported for doc generation") + .emit(); + return Err(1); + } else if !o.is_json() && show_coverage { + diag.struct_err( + "html output format isn't supported for the --show-coverage option", + ) + .emit(); + return Err(1); + } + Some(o) + } + Err(e) => { + diag.struct_err(&e).emit(); + return Err(1); + } + }, + None => None, + }; let crate_name = matches.opt_str("crate-name"); let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); let playground_url = matches.opt_str("playground-url"); @@ -553,6 +597,7 @@ impl Options { generate_search_filter, generate_redirect_pages, }, + output_format, }) } @@ -568,6 +613,9 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Han for flag in deprecated_flags.iter() { if matches.opt_present(flag) { + if *flag == "output-format" && matches.opt_present("show-coverage") { + continue; + } let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated", flag)); err.warn( diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c3c07e2e02c..f0b9ad2852f 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,26 +1,25 @@ use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; -use rustc::session::config::ErrorOutputType; -use rustc::session::DiagnosticOutput; -use rustc::session::{self, config}; use rustc::ty::{Ty, TyCtxt}; +use rustc_ast::ast::CRATE_NODE_ID; +use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_driver::abort_on_err; +use rustc_errors::emitter::{Emitter, EmitterWriter}; +use rustc_errors::json::JsonEmitter; use rustc_feature::UnstableFeatures; use rustc_hir::def::Namespace::TypeNS; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc_hir::HirId; use rustc_interface::interface; use rustc_resolve as resolve; +use rustc_session::config::ErrorOutputType; use rustc_session::lint; - -use rustc_attr as attr; -use rustc_errors::emitter::{Emitter, EmitterWriter}; -use rustc_errors::json::JsonEmitter; +use rustc_session::DiagnosticOutput; +use rustc_session::{config, Session}; use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; -use syntax::ast::CRATE_NODE_ID; use rustc_data_structures::sync::{self, Lrc}; use std::cell::RefCell; @@ -34,8 +33,8 @@ use crate::html::render::RenderInfo; use crate::passes::{self, Condition::*, ConditionalPass}; -pub use rustc::session::config::{CodegenOptions, DebuggingOptions, Input, Options}; -pub use rustc::session::search_paths::SearchPath; +pub use rustc_session::config::{CodegenOptions, DebuggingOptions, Input, Options}; +pub use rustc_session::search_paths::SearchPath; pub type ExternalPaths = FxHashMap, clean::TypeKind)>; @@ -68,7 +67,7 @@ pub struct DocContext<'tcx> { } impl<'tcx> DocContext<'tcx> { - pub fn sess(&self) -> &session::Session { + pub fn sess(&self) -> &Session { &self.tcx.sess } @@ -177,7 +176,7 @@ pub fn new_handler( Box::new( EmitterWriter::stderr( color_config, - source_map.map(|cm| cm as _), + source_map.map(|sm| sm as _), short, debugging_opts.teach, debugging_opts.terminal_width, @@ -228,6 +227,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt mut manual_passes, display_warnings, render_options, + output_format, .. } = options; @@ -283,7 +283,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt .filter_map(|lint| { // We don't want to whitelist *all* lints so let's // ignore those ones. - if whitelisted_lints.iter().any(|l| &lint.name == l) { + if whitelisted_lints.iter().any(|l| lint.name == l) { None } else { Some((lint::LintId::of(lint), lint::Allow)) @@ -385,6 +385,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let mut renderinfo = RenderInfo::default(); renderinfo.access_levels = access_levels; + renderinfo.output_format = output_format; let mut ctxt = DocContext { tcx, diff --git a/src/librustdoc/docfs.rs b/src/librustdoc/docfs.rs index ecc394a2bc9..9c9a00295c3 100644 --- a/src/librustdoc/docfs.rs +++ b/src/librustdoc/docfs.rs @@ -90,14 +90,14 @@ impl DocFS { let sender = self.errors.sender.clone().unwrap(); rayon::spawn(move || match fs::write(&path, &contents) { Ok(_) => { - sender - .send(None) - .expect(&format!("failed to send error on \"{}\"", path.display())); + sender.send(None).unwrap_or_else(|_| { + panic!("failed to send error on \"{}\"", path.display()) + }); } Err(e) => { - sender - .send(Some(format!("\"{}\": {}", path.display(), e))) - .expect(&format!("failed to send non-error on \"{}\"", path.display())); + sender.send(Some(format!("\"{}\": {}", path.display(), e))).unwrap_or_else( + |_| panic!("failed to send non-error on \"{}\"", path.display()), + ); } }); Ok(()) diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 744201a0050..41b8e66d265 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -2,10 +2,10 @@ //! manner (and with prettier names) before cleaning. pub use self::StructType::*; +use rustc_ast::ast; +use rustc_ast::ast::Name; use rustc_span::hygiene::MacroKind; use rustc_span::{self, Span}; -use syntax::ast; -use syntax::ast::Name; use rustc_hir as hir; use rustc_hir::def_id::CrateNum; @@ -44,7 +44,7 @@ impl Module<'hir> { vis: &'hir hir::Visibility<'hir>, ) -> Module<'hir> { Module { - name: name, + name, id: hir::CRATE_HIR_ID, vis, where_outer: rustc_span::DUMMY_SP, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index c3313ba63ef..e60ff37fd27 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -63,22 +63,10 @@ impl Buffer { Buffer { for_html: false, buffer: String::new() } } - crate fn is_empty(&self) -> bool { - self.buffer.is_empty() - } - crate fn into_inner(self) -> String { self.buffer } - crate fn insert_str(&mut self, idx: usize, s: &str) { - self.buffer.insert_str(idx, s); - } - - crate fn push_str(&mut self, s: &str) { - self.buffer.push_str(s); - } - // Intended for consumption by write! and writeln! (std::fmt) but without // the fmt::Result return type imposed by fmt::Write (and avoiding the trait // import). @@ -933,7 +921,7 @@ impl clean::Arguments { } } -impl clean::FunctionRetTy { +impl clean::FnRetTy { crate fn print(&self) -> impl fmt::Display + '_ { display_fn(move |f| match self { clean::Return(clean::Tuple(tys)) if tys.is_empty() => Ok(()), diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 1ea053605ec..02f1947c99e 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -1,6 +1,6 @@ //! Basic syntax highlighting functionality. //! -//! This module uses libsyntax's lexer to provide token-based highlighting for +//! This module uses librustc_ast's lexer to provide token-based highlighting for //! the HTML documentation generated by rustdoc. //! //! Use the `render_with_highlighting` to highlight some rust code. @@ -11,12 +11,12 @@ use std::fmt::Display; use std::io; use std::io::prelude::*; +use rustc_ast::token::{self, Token}; use rustc_parse::lexer; use rustc_session::parse::ParseSess; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym}; use rustc_span::{FileName, Span}; -use syntax::token::{self, Token}; /// Highlights `src`, returning the HTML output. pub fn render_with_highlighting( @@ -38,11 +38,11 @@ pub fn render_with_highlighting( } let sess = ParseSess::with_silent_emitter(); - let fm = sess + let sf = sess .source_map() .new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src.to_owned()); let highlight_result = rustc_driver::catch_fatal_errors(|| { - let lexer = lexer::StringReader::new(&sess, fm, None); + let lexer = lexer::StringReader::new(&sess, sf, None); let mut classifier = Classifier::new(lexer, sess.source_map()); let mut highlighted_source = vec![]; @@ -135,7 +135,7 @@ trait Writer { fn string(&mut self, text: T, klass: Class) -> io::Result<()>; } -// Implement `Writer` for anthing that can be written to, this just implements +// Implement `Writer` for anything that can be written to, this just implements // the default rustdoc behaviour. impl Writer for U { fn string(&mut self, text: T, klass: Class) -> io::Result<()> { diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 4a0f4e5a4c9..0b2b0cdc18b 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -62,7 +62,7 @@ impl<'a> From<&'a clean::Item> for ItemType { fn from(item: &'a clean::Item) -> ItemType { let inner = match item.inner { clean::StrippedItem(box ref item) => item, - ref inner @ _ => inner, + ref inner => inner, }; match *inner { @@ -194,7 +194,7 @@ impl fmt::Display for ItemType { } } -pub const NAMESPACE_TYPE: &'static str = "t"; -pub const NAMESPACE_VALUE: &'static str = "v"; -pub const NAMESPACE_MACRO: &'static str = "m"; -pub const NAMESPACE_KEYWORD: &'static str = "k"; +pub const NAMESPACE_TYPE: &str = "t"; +pub const NAMESPACE_VALUE: &str = "v"; +pub const NAMESPACE_MACRO: &str = "m"; +pub const NAMESPACE_KEYWORD: &str = "k"; diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c87964af020..e13bf270440 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -33,7 +33,7 @@ use crate::html::highlight; use crate::html::toc::TocBuilder; use crate::test; -use pulldown_cmark::{html, CowStr, Event, Options, Parser, Tag}; +use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag}; #[cfg(test)] mod tests; @@ -189,10 +189,15 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { let compile_fail; let ignore; let edition; - if let Some(Event::Start(Tag::CodeBlock(lang))) = event { - let parse_result = LangString::parse(&lang, self.check_error_codes, false); + if let Some(Event::Start(Tag::CodeBlock(kind))) = event { + let parse_result = match kind { + CodeBlockKind::Fenced(ref lang) => { + LangString::parse(&lang, self.check_error_codes, false) + } + CodeBlockKind::Indented => LangString::all_false(), + }; if !parse_result.rust { - return Some(Event::Start(Tag::CodeBlock(lang))); + return Some(Event::Start(Tag::CodeBlock(kind))); } compile_fail = parse_result.compile_fail; ignore = parse_result.ignore; @@ -291,7 +296,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { "" } )), - playground_button.as_ref().map(String::as_str), + playground_button.as_deref(), Some((s1.as_str(), s2)), )); Some(Event::Html(s.into())) @@ -310,7 +315,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { "" } )), - playground_button.as_ref().map(String::as_str), + playground_button.as_deref(), None, )); Some(Event::Html(s.into())) @@ -370,11 +375,11 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator for HeadingLinks<'a, } let event = self.inner.next(); - if let Some(Event::Start(Tag::Header(level))) = event { + if let Some(Event::Start(Tag::Heading(level))) = event { let mut id = String::new(); for event in &mut self.inner { match &event { - Event::End(Tag::Header(..)) => break, + Event::End(Tag::Heading(..)) => break, Event::Text(text) | Event::Code(text) => { id.extend(text.chars().filter_map(slugify)); } @@ -391,10 +396,10 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator for HeadingLinks<'a, let mut html_header = String::new(); html::push_html(&mut html_header, self.buf.iter().cloned()); let sec = builder.push(level as u32, html_header, id.clone()); - self.buf.push_front(Event::InlineHtml(format!("{} ", sec).into())); + self.buf.push_front(Event::Html(format!("{} ", sec).into())); } - self.buf.push_back(Event::InlineHtml(format!("", level).into())); + self.buf.push_back(Event::Html(format!("", level).into())); let start_tags = format!( "\ @@ -402,7 +407,7 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator for HeadingLinks<'a, id = id, level = level ); - return Some(Event::InlineHtml(start_tags.into())); + return Some(Event::Html(start_tags.into())); } event } @@ -460,7 +465,7 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { } _ => true, }; - return if is_allowed_tag == false { + return if !is_allowed_tag { if is_start { Some(Event::Start(Tag::Paragraph)) } else { @@ -556,40 +561,44 @@ pub fn find_testable_code( error_codes: ErrorCodes, enable_per_target_ignores: bool, ) { - let mut parser = Parser::new(doc); + let mut parser = Parser::new(doc).into_offset_iter(); let mut prev_offset = 0; let mut nb_lines = 0; let mut register_header = None; - while let Some(event) = parser.next() { + while let Some((event, offset)) = parser.next() { match event { - Event::Start(Tag::CodeBlock(s)) => { - let offset = parser.get_offset(); - - let block_info = if s.is_empty() { - LangString::all_false() - } else { - LangString::parse(&*s, error_codes, enable_per_target_ignores) + Event::Start(Tag::CodeBlock(kind)) => { + let block_info = match kind { + CodeBlockKind::Fenced(ref lang) => { + if lang.is_empty() { + LangString::all_false() + } else { + LangString::parse(lang, error_codes, enable_per_target_ignores) + } + } + CodeBlockKind::Indented => LangString::all_false(), }; if !block_info.rust { continue; } + let mut test_s = String::new(); - while let Some(Event::Text(s)) = parser.next() { + while let Some((Event::Text(s), _)) = parser.next() { test_s.push_str(&s); } - let text = test_s .lines() .map(|l| map_line(l).for_code()) .collect::>>() .join("\n"); - nb_lines += doc[prev_offset..offset].lines().count(); - let line = tests.get_line() + nb_lines; + + nb_lines += doc[prev_offset..offset.start].lines().count(); + let line = tests.get_line() + nb_lines + 1; tests.add_test(text, block_info, line); - prev_offset = offset; + prev_offset = offset.start; } - Event::Start(Tag::Header(level)) => { + Event::Start(Tag::Heading(level)) => { register_header = Some(level as u32); } Event::Text(ref s) if register_header.is_some() => { @@ -662,7 +671,7 @@ impl LangString { "" => {} "should_panic" => { data.should_panic = true; - seen_rust_tags = seen_other_tags == false; + seen_rust_tags = !seen_other_tags; } "no_run" => { data.no_run = true; @@ -698,7 +707,7 @@ impl LangString { x if x.starts_with("edition") => { data.edition = x[7..].parse::().ok(); } - x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => { + x if allow_error_code_check && x.starts_with('E') && x.len() == 5 => { if x[1..].parse::().is_ok() { data.error_codes.push(x.to_owned()); seen_rust_tags = !seen_other_tags || seen_rust_tags; @@ -729,7 +738,7 @@ impl Markdown<'_> { return String::new(); } let replacer = |_: &str, s: &str| { - if let Some(&(_, ref replace)) = links.into_iter().find(|link| &*link.0 == s) { + if let Some(&(_, ref replace)) = links.iter().find(|link| &*link.0 == s) { Some((replace.clone(), s.to_owned())) } else { None @@ -783,7 +792,7 @@ impl MarkdownHtml<'_> { // Treat inline HTML as plain text. let p = p.map(|event| match event { - Event::Html(text) | Event::InlineHtml(text) => Event::Text(text), + Event::Html(text) => Event::Text(text), _ => event, }); @@ -807,7 +816,7 @@ impl MarkdownSummaryLine<'_> { } let replacer = |_: &str, s: &str| { - if let Some(&(_, ref replace)) = links.into_iter().find(|link| &*link.0 == s) { + if let Some(&(_, ref replace)) = links.iter().find(|link| &*link.0 == s) { Some((replace.clone(), s.to_owned())) } else { None @@ -835,17 +844,13 @@ pub fn plain_summary_line(md: &str) -> String { type Item = String; fn next(&mut self) -> Option { - let next_event = self.inner.next(); - if next_event.is_none() { - return None; - } - let next_event = next_event.unwrap(); + let next_event = self.inner.next()?; let (ret, is_in) = match next_event { Event::Start(Tag::Paragraph) => (None, 1), - Event::Start(Tag::Header(_)) => (None, 1), + Event::Start(Tag::Heading(_)) => (None, 1), Event::Code(code) => (Some(format!("`{}`", code)), 0), Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), - Event::End(Tag::Paragraph) | Event::End(Tag::Header(_)) => (None, -1), + Event::End(Tag::Paragraph) | Event::End(Tag::Heading(_)) => (None, -1), _ => (None, 0), }; if is_in > 0 || (is_in < 0 && self.is_in > 0) { @@ -860,12 +865,8 @@ pub fn plain_summary_line(md: &str) -> String { } } let mut s = String::with_capacity(md.len() * 3 / 2); - let mut p = ParserWrapper { inner: Parser::new(md), is_in: 0, is_first: true }; - while let Some(t) = p.next() { - if !t.is_empty() { - s.push_str(&t); - } - } + let p = ParserWrapper { inner: Parser::new(md), is_in: 0, is_first: true }; + p.filter(|t| !t.is_empty()).for_each(|i| s.push_str(&i)); s } @@ -940,68 +941,79 @@ crate fn rust_code_blocks(md: &str) -> Vec { return code_blocks; } - let mut p = Parser::new_ext(md, opts()); - - let mut code_block_start = 0; - let mut code_start = 0; - let mut is_fenced = false; - let mut previous_offset = 0; - let mut in_rust_code_block = false; - while let Some(event) = p.next() { - let offset = p.get_offset(); + let mut p = Parser::new_ext(md, opts()).into_offset_iter(); + while let Some((event, offset)) = p.next() { match event { Event::Start(Tag::CodeBlock(syntax)) => { - let lang_string = if syntax.is_empty() { - LangString::all_false() - } else { - LangString::parse(&*syntax, ErrorCodes::Yes, false) - }; - - if lang_string.rust { - in_rust_code_block = true; - - code_start = offset; - code_block_start = match md[previous_offset..offset].find("```") { - Some(fence_idx) => { - is_fenced = true; - previous_offset + fence_idx + let (syntax, code_start, code_end, range, is_fenced) = match syntax { + CodeBlockKind::Fenced(syntax) => { + let syntax = syntax.as_ref(); + let lang_string = if syntax.is_empty() { + LangString::all_false() + } else { + LangString::parse(&*syntax, ErrorCodes::Yes, false) + }; + if !lang_string.rust { + continue; } - None => { - is_fenced = false; - offset + let syntax = if syntax.is_empty() { None } else { Some(syntax.to_owned()) }; + let (code_start, mut code_end) = match p.next() { + Some((Event::Text(_), offset)) => (offset.start, offset.end), + Some((_, sub_offset)) => { + let code = Range { start: sub_offset.start, end: sub_offset.start }; + code_blocks.push(RustCodeBlock { + is_fenced: true, + range: offset, + code, + syntax, + }); + continue; + } + None => { + let code = Range { start: offset.end, end: offset.end }; + code_blocks.push(RustCodeBlock { + is_fenced: true, + range: offset, + code, + syntax, + }); + continue; + } + }; + while let Some((Event::Text(_), offset)) = p.next() { + code_end = offset.end; } - }; - } - } - Event::End(Tag::CodeBlock(syntax)) if in_rust_code_block => { - in_rust_code_block = false; - - let code_block_end = if is_fenced { - let fence_str = &md[previous_offset..offset].chars().rev().collect::(); - fence_str - .find("```") - .map(|fence_idx| offset - fence_idx) - .unwrap_or_else(|| offset) - } else if md.as_bytes().get(offset).map(|b| *b == b'\n').unwrap_or_default() { - offset - 1 - } else { - offset + (syntax, code_start, code_end, offset, true) + } + CodeBlockKind::Indented => { + // The ending of the offset goes too far sometime so we reduce it by one in + // these cases. + if offset.end > offset.start + && md.get(offset.end..=offset.end) == Some(&"\n") + { + ( + None, + offset.start, + offset.end, + Range { start: offset.start, end: offset.end - 1 }, + false, + ) + } else { + (None, offset.start, offset.end, offset, false) + } + } }; - let code_end = if is_fenced { previous_offset } else { code_block_end }; - code_blocks.push(RustCodeBlock { is_fenced, - range: Range { start: code_block_start, end: code_block_end }, + range, code: Range { start: code_start, end: code_end }, - syntax: if !syntax.is_empty() { Some(syntax.into_string()) } else { None }, + syntax, }); } _ => (), } - - previous_offset = offset; } code_blocks diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 6a23b230e12..eb7a367acf4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -57,10 +57,9 @@ use rustc_span::source_map::FileName; use rustc_span::symbol::{sym, Symbol}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; -use syntax::ast; -use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy}; -use crate::config::RenderOptions; +use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, TypeKind}; +use crate::config::{OutputFormat, RenderOptions}; use crate::docfs::{DocFS, ErrorStorage, PathError}; use crate::doctree; use crate::html::escape::Escape; @@ -86,7 +85,7 @@ pub type NameDoc = (String, Option); crate fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { crate::html::format::display_fn(move |f| { - if !v.ends_with("/") && !v.is_empty() { write!(f, "{}/", v) } else { write!(f, "{}", v) } + if !v.ends_with('/') && !v.is_empty() { write!(f, "{}/", v) } else { write!(f, "{}", v) } }) } @@ -270,6 +269,7 @@ pub struct RenderInfo { pub deref_trait_did: Option, pub deref_mut_trait_did: Option, pub owned_box_did: Option, + pub output_format: Option, } // Helper structs for rendering items/sidebars and carrying along contextual @@ -302,19 +302,25 @@ impl Serialize for IndexItem { /// A type used for the search index. #[derive(Debug)] -struct Type { +struct RenderType { + ty: Option, + idx: Option, name: Option, - generics: Option>, + generics: Option>, } -impl Serialize for Type { +impl Serialize for RenderType { fn serialize(&self, serializer: S) -> Result where S: Serializer, { if let Some(name) = &self.name { let mut seq = serializer.serialize_seq(None)?; - seq.serialize_element(&name)?; + if let Some(id) = self.idx { + seq.serialize_element(&id)?; + } else { + seq.serialize_element(&name)?; + } if let Some(generics) = &self.generics { seq.serialize_element(&generics)?; } @@ -325,11 +331,32 @@ impl Serialize for Type { } } +/// A type used for the search index. +#[derive(Debug)] +struct Generic { + name: String, + defid: Option, + idx: Option, +} + +impl Serialize for Generic { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if let Some(id) = self.idx { + serializer.serialize_some(&id) + } else { + serializer.serialize_some(&self.name) + } + } +} + /// Full type of functions/methods in the search index. #[derive(Debug)] struct IndexItemFunctionType { - inputs: Vec, - output: Option>, + inputs: Vec, + output: Option>, } impl Serialize for IndexItemFunctionType { @@ -340,8 +367,8 @@ impl Serialize for IndexItemFunctionType { // If we couldn't figure out a type, just write `null`. let mut iter = self.inputs.iter(); if match self.output { - Some(ref output) => iter.chain(output.iter()).any(|ref i| i.name.is_none()), - None => iter.any(|ref i| i.name.is_none()), + Some(ref output) => iter.chain(output.iter()).any(|ref i| i.ty.name.is_none()), + None => iter.any(|ref i| i.ty.name.is_none()), } { serializer.serialize_none() } else { @@ -359,6 +386,31 @@ impl Serialize for IndexItemFunctionType { } } +#[derive(Debug)] +pub struct TypeWithKind { + ty: RenderType, + kind: TypeKind, +} + +impl From<(RenderType, TypeKind)> for TypeWithKind { + fn from(x: (RenderType, TypeKind)) -> TypeWithKind { + TypeWithKind { ty: x.0, kind: x.1 } + } +} + +impl Serialize for TypeWithKind { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(None)?; + seq.serialize_element(&self.ty.name)?; + let x: ItemType = self.kind.into(); + seq.serialize_element(&x)?; + seq.end() + } +} + thread_local!(static CACHE_KEY: RefCell> = Default::default()); thread_local!(pub static CURRENT_DEPTH: Cell = Cell::new(0)); @@ -1313,7 +1365,8 @@ impl Context {