mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Auto merge of #91019 - JohnTitor:rollup-q95ra7r, r=JohnTitor
Rollup of 8 pull requests Successful merges: - #90386 (Add `-Zassert-incr-state` to assert state of incremental cache) - #90438 (Clean up mess for --show-coverage documentation) - #90480 (Mention `Vec::remove` in `Vec::swap_remove`'s docs) - #90607 (Make slice->str conversion and related functions `const`) - #90750 (rustdoc: Replace where-bounded Clean impl with simple function) - #90895 (require full validity when determining the discriminant of a value) - #90989 (Avoid suggesting literal formatting that turns into member access) - #91002 (rustc: Remove `#[rustc_synthetic]`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
cc946fcd32
@ -1338,10 +1338,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
pure_wrt_drop: false,
|
||||
bounds: hir_bounds,
|
||||
span: self.lower_span(span),
|
||||
kind: hir::GenericParamKind::Type {
|
||||
default: None,
|
||||
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
|
||||
},
|
||||
kind: hir::GenericParamKind::Type { default: None, synthetic: true },
|
||||
});
|
||||
|
||||
hir::TyKind::Path(hir::QPath::Resolved(
|
||||
@ -1954,12 +1951,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
default: default.as_ref().map(|x| {
|
||||
self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Other))
|
||||
}),
|
||||
synthetic: param
|
||||
.attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.has_name(sym::rustc_synthetic))
|
||||
.map(|_| hir::SyntheticTyParamKind::FromAttr)
|
||||
.next(),
|
||||
synthetic: false,
|
||||
};
|
||||
|
||||
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
|
||||
|
@ -265,6 +265,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
sym::discriminant_value => {
|
||||
let place = self.deref_operand(&args[0])?;
|
||||
if M::enforce_validity(self) {
|
||||
// This is 'using' the value, so make sure the validity invariant is satisfied.
|
||||
// (Also see https://github.com/rust-lang/rust/pull/89764.)
|
||||
self.validate_operand(&place.into())?;
|
||||
}
|
||||
|
||||
let discr_val = self.read_discriminant(&place.into())?.0;
|
||||
self.write_scalar(discr_val, dest)?;
|
||||
}
|
||||
|
@ -304,6 +304,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
Discriminant(place) => {
|
||||
let op = self.eval_place_to_op(place, None)?;
|
||||
if M::enforce_validity(self) {
|
||||
// This is 'using' the value, so make sure the validity invariant is satisfied.
|
||||
// (Also see https://github.com/rust-lang/rust/pull/89764.)
|
||||
self.validate_operand(&op)?;
|
||||
}
|
||||
|
||||
let discr_val = self.read_discriminant(&op)?.0;
|
||||
self.write_scalar(discr_val, &dest)?;
|
||||
}
|
||||
|
@ -601,7 +601,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
TEST, rustc_expected_cgu_reuse, Normal,
|
||||
template!(List: r#"cfg = "...", module = "...", kind = "...""#),
|
||||
),
|
||||
rustc_attr!(TEST, rustc_synthetic, Normal, template!(Word)),
|
||||
rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word)),
|
||||
rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word)),
|
||||
rustc_attr!(TEST, rustc_def_path, Normal, template!(Word)),
|
||||
|
@ -504,7 +504,7 @@ pub enum GenericParamKind<'hir> {
|
||||
},
|
||||
Type {
|
||||
default: Option<&'hir Ty<'hir>>,
|
||||
synthetic: Option<SyntheticTyParamKind>,
|
||||
synthetic: bool,
|
||||
},
|
||||
Const {
|
||||
ty: &'hir Ty<'hir>,
|
||||
@ -577,16 +577,6 @@ impl Generics<'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Synthetic type parameters are converted to another form during lowering; this allows
|
||||
/// us to track the original form they had, and is useful for error messages.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum SyntheticTyParamKind {
|
||||
ImplTrait,
|
||||
// Created by the `#[rustc_synthetic]` attribute.
|
||||
FromAttr,
|
||||
}
|
||||
|
||||
/// A where-clause in a definition.
|
||||
#[derive(Debug, HashStable_Generic)]
|
||||
pub struct WhereClause<'hir> {
|
||||
|
@ -6,6 +6,7 @@ use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::OnDiskCache;
|
||||
use rustc_serialize::opaque::Decoder;
|
||||
use rustc_serialize::Decodable;
|
||||
use rustc_session::config::IncrementalStateAssertion;
|
||||
use rustc_session::Session;
|
||||
use std::path::Path;
|
||||
|
||||
@ -16,6 +17,7 @@ use super::work_product;
|
||||
|
||||
type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LoadResult<T> {
|
||||
Ok { data: T },
|
||||
DataOutOfDate,
|
||||
@ -24,6 +26,26 @@ pub enum LoadResult<T> {
|
||||
|
||||
impl<T: Default> LoadResult<T> {
|
||||
pub fn open(self, sess: &Session) -> T {
|
||||
// Check for errors when using `-Zassert-incremental-state`
|
||||
match (sess.opts.assert_incr_state, &self) {
|
||||
(Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => {
|
||||
sess.fatal(
|
||||
"We asserted that the incremental cache should not be loaded, \
|
||||
but it was loaded.",
|
||||
);
|
||||
}
|
||||
(
|
||||
Some(IncrementalStateAssertion::Loaded),
|
||||
LoadResult::Error { .. } | LoadResult::DataOutOfDate,
|
||||
) => {
|
||||
sess.fatal(
|
||||
"We asserted that an existing incremental cache directory should \
|
||||
be successfully loaded, but it was not.",
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match self {
|
||||
LoadResult::Error { message } => {
|
||||
sess.warn(&message);
|
||||
@ -33,7 +55,7 @@ impl<T: Default> LoadResult<T> {
|
||||
if let Err(err) = delete_all_session_dir_contents(sess) {
|
||||
sess.err(&format!(
|
||||
"Failed to delete invalidated or incompatible \
|
||||
incremental compilation session directory contents `{}`: {}.",
|
||||
incremental compilation session directory contents `{}`: {}.",
|
||||
dep_graph_path(sess).display(),
|
||||
err
|
||||
));
|
||||
|
@ -636,6 +636,7 @@ fn test_debugging_options_tracking_hash() {
|
||||
|
||||
// Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
|
||||
// This list is in alphabetical order.
|
||||
untracked!(assert_incr_state, Some(String::from("loaded")));
|
||||
untracked!(ast_json, true);
|
||||
untracked!(ast_json_noexpand, true);
|
||||
untracked!(borrowck, String::from("other"));
|
||||
|
@ -3,7 +3,6 @@ use crate::ty;
|
||||
use crate::ty::subst::{Subst, SubstsRef};
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
@ -13,14 +12,8 @@ use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predi
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub enum GenericParamDefKind {
|
||||
Lifetime,
|
||||
Type {
|
||||
has_default: bool,
|
||||
object_lifetime_default: ObjectLifetimeDefault,
|
||||
synthetic: Option<hir::SyntheticTyParamKind>,
|
||||
},
|
||||
Const {
|
||||
has_default: bool,
|
||||
},
|
||||
Type { has_default: bool, object_lifetime_default: ObjectLifetimeDefault, synthetic: bool },
|
||||
Const { has_default: bool },
|
||||
}
|
||||
|
||||
impl GenericParamDefKind {
|
||||
@ -202,15 +195,7 @@ impl<'tcx> Generics {
|
||||
/// Returns `true` if `params` has `impl Trait`.
|
||||
pub fn has_impl_trait(&'tcx self) -> bool {
|
||||
self.params.iter().any(|param| {
|
||||
matches!(
|
||||
param.kind,
|
||||
ty::GenericParamDefKind::Type {
|
||||
synthetic: Some(
|
||||
hir::SyntheticTyParamKind::ImplTrait | hir::SyntheticTyParamKind::FromAttr,
|
||||
),
|
||||
..
|
||||
}
|
||||
)
|
||||
matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1810,12 +1810,10 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
||||
let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| {
|
||||
!matches!(
|
||||
p.kind,
|
||||
hir::GenericParamKind::Type {
|
||||
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
|
||||
..
|
||||
} | hir::GenericParamKind::Lifetime {
|
||||
kind: hir::LifetimeParamKind::Elided,
|
||||
}
|
||||
hir::GenericParamKind::Type { synthetic: true, .. }
|
||||
| hir::GenericParamKind::Lifetime {
|
||||
kind: hir::LifetimeParamKind::Elided,
|
||||
}
|
||||
)
|
||||
}) {
|
||||
(param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
|
||||
@ -2042,12 +2040,10 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
|
||||
if let Some(param) = generics.params.iter().find(|p| {
|
||||
!matches!(
|
||||
p.kind,
|
||||
hir::GenericParamKind::Type {
|
||||
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
|
||||
..
|
||||
} | hir::GenericParamKind::Lifetime {
|
||||
kind: hir::LifetimeParamKind::Elided
|
||||
}
|
||||
hir::GenericParamKind::Type { synthetic: true, .. }
|
||||
| hir::GenericParamKind::Lifetime {
|
||||
kind: hir::LifetimeParamKind::Elided
|
||||
}
|
||||
)
|
||||
}) {
|
||||
(param.span.shrink_to_lo(), "'a, ".to_string())
|
||||
|
@ -165,6 +165,18 @@ pub enum LinkerPluginLto {
|
||||
Disabled,
|
||||
}
|
||||
|
||||
/// Used with `-Z assert-incr-state`.
|
||||
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||
pub enum IncrementalStateAssertion {
|
||||
/// Found and loaded an existing session directory.
|
||||
///
|
||||
/// Note that this says nothing about whether any particular query
|
||||
/// will be found to be red or green.
|
||||
Loaded,
|
||||
/// Did not load an existing session directory.
|
||||
NotLoaded,
|
||||
}
|
||||
|
||||
impl LinkerPluginLto {
|
||||
pub fn enabled(&self) -> bool {
|
||||
match *self {
|
||||
@ -704,6 +716,7 @@ pub fn host_triple() -> &'static str {
|
||||
impl Default for Options {
|
||||
fn default() -> Options {
|
||||
Options {
|
||||
assert_incr_state: None,
|
||||
crate_types: Vec::new(),
|
||||
optimize: OptLevel::No,
|
||||
debuginfo: DebugInfo::None,
|
||||
@ -1626,6 +1639,21 @@ fn select_debuginfo(
|
||||
}
|
||||
}
|
||||
|
||||
crate fn parse_assert_incr_state(
|
||||
opt_assertion: &Option<String>,
|
||||
error_format: ErrorOutputType,
|
||||
) -> Option<IncrementalStateAssertion> {
|
||||
match opt_assertion {
|
||||
Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
|
||||
Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
|
||||
Some(s) => early_error(
|
||||
error_format,
|
||||
&format!("unexpected incremental state assertion value: {}", s),
|
||||
),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_native_lib_kind(
|
||||
matches: &getopts::Matches,
|
||||
kind: &str,
|
||||
@ -2015,6 +2043,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
|
||||
let incremental = cg.incremental.as_ref().map(PathBuf::from);
|
||||
|
||||
let assert_incr_state =
|
||||
parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format);
|
||||
|
||||
if debugging_opts.profile && incremental.is_some() {
|
||||
early_error(
|
||||
error_format,
|
||||
@ -2179,6 +2210,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
};
|
||||
|
||||
Options {
|
||||
assert_incr_state,
|
||||
crate_types,
|
||||
optimize: opt_level,
|
||||
debuginfo,
|
||||
|
@ -4,7 +4,6 @@ use crate::early_error;
|
||||
use crate::lint;
|
||||
use crate::search_paths::SearchPath;
|
||||
use crate::utils::NativeLib;
|
||||
|
||||
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
|
||||
use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
|
||||
|
||||
@ -150,6 +149,7 @@ top_level_options!(
|
||||
/// If `Some`, enable incremental compilation, using the given
|
||||
/// directory to store intermediate results.
|
||||
incremental: Option<PathBuf> [UNTRACKED],
|
||||
assert_incr_state: Option<IncrementalStateAssertion> [UNTRACKED],
|
||||
|
||||
debugging_opts: DebuggingOptions [SUBSTRUCT],
|
||||
prints: Vec<PrintRequest> [UNTRACKED],
|
||||
@ -1046,6 +1046,9 @@ options! {
|
||||
"make cfg(version) treat the current version as incomplete (default: no)"),
|
||||
asm_comments: bool = (false, parse_bool, [TRACKED],
|
||||
"generate comments into the assembly (may change behavior) (default: no)"),
|
||||
assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
||||
"assert that the incremental cache is in given state: \
|
||||
either `loaded` or `not-loaded`."),
|
||||
ast_json: bool = (false, parse_bool, [UNTRACKED],
|
||||
"print the AST as JSON and halt (default: no)"),
|
||||
ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
|
||||
|
@ -1148,7 +1148,6 @@ symbols! {
|
||||
rustc_std_internal_symbol,
|
||||
rustc_strict_coherence,
|
||||
rustc_symbol_name,
|
||||
rustc_synthetic,
|
||||
rustc_test_marker,
|
||||
rustc_then_this_would_need,
|
||||
rustc_trivial_field_reads,
|
||||
|
@ -290,9 +290,10 @@ fn suggest_restriction(
|
||||
} else {
|
||||
// Trivial case: `T` needs an extra bound: `T: Bound`.
|
||||
let (sp, suggestion) = match (
|
||||
generics.params.iter().find(|p| {
|
||||
!matches!(p.kind, hir::GenericParamKind::Type { synthetic: Some(_), .. })
|
||||
}),
|
||||
generics
|
||||
.params
|
||||
.iter()
|
||||
.find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),
|
||||
super_traits,
|
||||
) {
|
||||
(_, None) => predicate_constraint(
|
||||
|
@ -464,16 +464,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
.params
|
||||
.iter()
|
||||
.filter(|param| {
|
||||
matches!(
|
||||
param.kind,
|
||||
ty::GenericParamDefKind::Type {
|
||||
synthetic: Some(
|
||||
hir::SyntheticTyParamKind::ImplTrait
|
||||
| hir::SyntheticTyParamKind::FromAttr
|
||||
),
|
||||
..
|
||||
}
|
||||
)
|
||||
matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
|
||||
})
|
||||
.count()
|
||||
} else {
|
||||
|
@ -607,10 +607,7 @@ fn compare_number_of_generics<'tcx>(
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|p| match p.kind {
|
||||
GenericParamKind::Type {
|
||||
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
|
||||
..
|
||||
} => Some(p.span),
|
||||
GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
@ -627,10 +624,7 @@ fn compare_number_of_generics<'tcx>(
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|p| match p.kind {
|
||||
GenericParamKind::Type {
|
||||
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
|
||||
..
|
||||
} => Some(p.span),
|
||||
GenericParamKind::Type { synthetic: true, .. } => Some(p.span),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
@ -823,7 +817,7 @@ fn compare_synthetic_generics<'tcx>(
|
||||
match (impl_synthetic, trait_synthetic) {
|
||||
// The case where the impl method uses `impl Trait` but the trait method uses
|
||||
// explicit generics
|
||||
(Some(hir::SyntheticTyParamKind::ImplTrait), None) => {
|
||||
(true, false) => {
|
||||
err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
|
||||
(|| {
|
||||
// try taking the name from the trait impl
|
||||
@ -864,7 +858,7 @@ fn compare_synthetic_generics<'tcx>(
|
||||
}
|
||||
// The case where the trait method uses `impl Trait`, but the impl method uses
|
||||
// explicit generics.
|
||||
(None, Some(hir::SyntheticTyParamKind::ImplTrait)) => {
|
||||
(false, true) => {
|
||||
err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
|
||||
(|| {
|
||||
let impl_m = impl_m.def_id.as_local()?;
|
||||
|
@ -2025,7 +2025,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.to_def_id());
|
||||
let generic_param = generics.type_param(¶m, self.tcx);
|
||||
if let ty::GenericParamDefKind::Type { synthetic: Some(..), .. } = generic_param.kind {
|
||||
if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param.kind {
|
||||
return;
|
||||
}
|
||||
let param_def_id = generic_param.def_id;
|
||||
|
@ -317,6 +317,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
.span_to_snippet(lit.span)
|
||||
.unwrap_or_else(|_| "<numeric literal>".to_owned());
|
||||
|
||||
// If this is a floating point literal that ends with '.',
|
||||
// get rid of it to stop this from becoming a member access.
|
||||
let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
|
||||
|
||||
err.span_suggestion(
|
||||
lit.span,
|
||||
&format!(
|
||||
@ -324,7 +328,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
like `{}`",
|
||||
concrete_type
|
||||
),
|
||||
format!("{}_{}", snippet, concrete_type),
|
||||
format!("{snippet}_{concrete_type}"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
@ -1490,7 +1494,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
Node::GenericParam(param) => {
|
||||
let mut impl_trait = false;
|
||||
let has_bounds =
|
||||
if let hir::GenericParamKind::Type { synthetic: Some(_), .. } =
|
||||
if let hir::GenericParamKind::Type { synthetic: true, .. } =
|
||||
¶m.kind
|
||||
{
|
||||
// We've found `fn foo(x: impl Trait)` instead of
|
||||
|
@ -1543,7 +1543,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
kind: ty::GenericParamDefKind::Type {
|
||||
has_default: false,
|
||||
object_lifetime_default: rl::Set1::Empty,
|
||||
synthetic: None,
|
||||
synthetic: false,
|
||||
},
|
||||
});
|
||||
|
||||
@ -1673,7 +1673,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
kind: ty::GenericParamDefKind::Type {
|
||||
has_default: false,
|
||||
object_lifetime_default: rl::Set1::Empty,
|
||||
synthetic: None,
|
||||
synthetic: false,
|
||||
},
|
||||
}));
|
||||
}
|
||||
@ -1690,7 +1690,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
kind: ty::GenericParamDefKind::Type {
|
||||
has_default: false,
|
||||
object_lifetime_default: rl::Set1::Empty,
|
||||
synthetic: None,
|
||||
synthetic: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -1272,6 +1272,9 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// The removed element is replaced by the last element of the vector.
|
||||
///
|
||||
/// This does not preserve ordering, but is *O*(1).
|
||||
/// If you need to preserve the element order, use [`remove`] instead.
|
||||
///
|
||||
/// [`remove`]: Vec::remove
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@ -1368,7 +1371,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// shifting all elements after it to the left.
|
||||
///
|
||||
/// Note: Because this shifts over the remaining elements, it has a
|
||||
/// worst-case performance of O(n). If you don't need the order of elements
|
||||
/// worst-case performance of *O*(*n*). If you don't need the order of elements
|
||||
/// to be preserved, use [`swap_remove`] instead.
|
||||
///
|
||||
/// [`swap_remove`]: Vec::swap_remove
|
||||
|
@ -25,6 +25,7 @@
|
||||
#![feature(const_btree_new)]
|
||||
#![feature(const_default_impls)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_str_from_utf8)]
|
||||
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
@ -1,3 +1,4 @@
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering::{Equal, Greater, Less};
|
||||
use std::str::{from_utf8, from_utf8_unchecked};
|
||||
@ -883,6 +884,33 @@ fn test_is_utf8() {
|
||||
assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_const_is_utf8() {
|
||||
const _: () = {
|
||||
// deny overlong encodings
|
||||
assert!(from_utf8(&[0xc0, 0x80]).is_err());
|
||||
assert!(from_utf8(&[0xc0, 0xae]).is_err());
|
||||
assert!(from_utf8(&[0xe0, 0x80, 0x80]).is_err());
|
||||
assert!(from_utf8(&[0xe0, 0x80, 0xaf]).is_err());
|
||||
assert!(from_utf8(&[0xe0, 0x81, 0x81]).is_err());
|
||||
assert!(from_utf8(&[0xf0, 0x82, 0x82, 0xac]).is_err());
|
||||
assert!(from_utf8(&[0xf4, 0x90, 0x80, 0x80]).is_err());
|
||||
|
||||
// deny surrogates
|
||||
assert!(from_utf8(&[0xED, 0xA0, 0x80]).is_err());
|
||||
assert!(from_utf8(&[0xED, 0xBF, 0xBF]).is_err());
|
||||
|
||||
assert!(from_utf8(&[0xC2, 0x80]).is_ok());
|
||||
assert!(from_utf8(&[0xDF, 0xBF]).is_ok());
|
||||
assert!(from_utf8(&[0xE0, 0xA0, 0x80]).is_ok());
|
||||
assert!(from_utf8(&[0xED, 0x9F, 0xBF]).is_ok());
|
||||
assert!(from_utf8(&[0xEE, 0x80, 0x80]).is_ok());
|
||||
assert!(from_utf8(&[0xEF, 0xBF, 0xBF]).is_ok());
|
||||
assert!(from_utf8(&[0xF0, 0x90, 0x80, 0x80]).is_ok());
|
||||
assert!(from_utf8(&[0xF4, 0x8F, 0xBF, 0xBF]).is_ok());
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_utf8_mostly_ascii() {
|
||||
// deny invalid bytes embedded in long stretches of ascii
|
||||
@ -895,13 +923,43 @@ fn from_utf8_mostly_ascii() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_from_utf8_mostly_ascii() {
|
||||
const _: () = {
|
||||
// deny invalid bytes embedded in long stretches of ascii
|
||||
let mut i = 32;
|
||||
while i < 64 {
|
||||
let mut data = [0; 128];
|
||||
data[i] = 0xC0;
|
||||
assert!(from_utf8(&data).is_err());
|
||||
data[i] = 0xC2;
|
||||
assert!(from_utf8(&data).is_err());
|
||||
|
||||
i = i + 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_utf8_error() {
|
||||
macro_rules! test {
|
||||
($input: expr, $expected_valid_up_to: expr, $expected_error_len: expr) => {
|
||||
($input: expr, $expected_valid_up_to:pat, $expected_error_len:pat) => {
|
||||
let error = from_utf8($input).unwrap_err();
|
||||
assert_eq!(error.valid_up_to(), $expected_valid_up_to);
|
||||
assert_eq!(error.error_len(), $expected_error_len);
|
||||
assert_matches!(error.valid_up_to(), $expected_valid_up_to);
|
||||
assert_matches!(error.error_len(), $expected_error_len);
|
||||
|
||||
const _: () = {
|
||||
match from_utf8($input) {
|
||||
Err(error) => {
|
||||
let valid_up_to = error.valid_up_to();
|
||||
let error_len = error.error_len();
|
||||
|
||||
assert!(matches!(valid_up_to, $expected_valid_up_to));
|
||||
assert!(matches!(error_len, $expected_error_len));
|
||||
}
|
||||
Ok(_) => unreachable!(),
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
test!(b"A\xC3\xA9 \xFF ", 4, Some(1));
|
||||
|
@ -97,6 +97,7 @@
|
||||
#![allow(explicit_outlives_requirements)]
|
||||
//
|
||||
// Library features for const fns:
|
||||
#![feature(const_align_offset)]
|
||||
#![feature(const_align_of_val)]
|
||||
#![feature(const_alloc_layout)]
|
||||
#![feature(const_arguments_as_str)]
|
||||
@ -130,6 +131,7 @@
|
||||
#![feature(const_size_of_val)]
|
||||
#![feature(const_slice_from_raw_parts)]
|
||||
#![feature(const_slice_ptr_len)]
|
||||
#![feature(const_str_from_utf8_unchecked_mut)]
|
||||
#![feature(const_swap)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_type_id)]
|
||||
@ -138,6 +140,7 @@
|
||||
#![feature(duration_consts_2)]
|
||||
#![feature(ptr_metadata)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(variant_count)]
|
||||
#![feature(const_array_from_ref)]
|
||||
#![feature(const_slice_from_ref)]
|
||||
|
@ -82,10 +82,16 @@ use super::Utf8Error;
|
||||
/// assert_eq!("💖", sparkle_heart);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
|
||||
run_utf8_validation(v)?;
|
||||
// SAFETY: Just ran validation.
|
||||
Ok(unsafe { from_utf8_unchecked(v) })
|
||||
#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")]
|
||||
pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
|
||||
// This should use `?` again, once it's `const`
|
||||
match run_utf8_validation(v) {
|
||||
Ok(_) => {
|
||||
// SAFETY: validation succeeded.
|
||||
Ok(unsafe { from_utf8_unchecked(v) })
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a mutable slice of bytes to a mutable string slice.
|
||||
@ -119,10 +125,16 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
|
||||
/// See the docs for [`Utf8Error`] for more details on the kinds of
|
||||
/// errors that can be returned.
|
||||
#[stable(feature = "str_mut_extras", since = "1.20.0")]
|
||||
pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
|
||||
run_utf8_validation(v)?;
|
||||
// SAFETY: Just ran validation.
|
||||
Ok(unsafe { from_utf8_unchecked_mut(v) })
|
||||
#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")]
|
||||
pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
|
||||
// This should use `?` again, once it's `const`
|
||||
match run_utf8_validation(v) {
|
||||
Ok(_) => {
|
||||
// SAFETY: validation succeeded.
|
||||
Ok(unsafe { from_utf8_unchecked_mut(v) })
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a slice of bytes to a string slice without checking
|
||||
@ -184,7 +196,8 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[stable(feature = "str_mut_extras", since = "1.20.0")]
|
||||
pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
|
||||
#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked_mut", issue = "91005")]
|
||||
pub const unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
|
||||
// SAFETY: the caller must guarantee that the bytes `v`
|
||||
// are valid UTF-8, thus the cast to `*mut str` is safe.
|
||||
// Also, the pointer dereference is safe because that pointer
|
||||
|
@ -72,9 +72,10 @@ impl Utf8Error {
|
||||
/// assert_eq!(1, error.valid_up_to());
|
||||
/// ```
|
||||
#[stable(feature = "utf8_error", since = "1.5.0")]
|
||||
#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn valid_up_to(&self) -> usize {
|
||||
pub const fn valid_up_to(&self) -> usize {
|
||||
self.valid_up_to
|
||||
}
|
||||
|
||||
@ -94,10 +95,15 @@ impl Utf8Error {
|
||||
///
|
||||
/// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html
|
||||
#[stable(feature = "utf8_error_error_len", since = "1.20.0")]
|
||||
#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn error_len(&self) -> Option<usize> {
|
||||
self.error_len.map(|len| len as usize)
|
||||
pub const fn error_len(&self) -> Option<usize> {
|
||||
// This should become `map` again, once it's `const`
|
||||
match self.error_len {
|
||||
Some(len) => Some(len as usize),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,25 +8,25 @@ use super::Utf8Error;
|
||||
/// The first byte is special, only want bottom 5 bits for width 2, 4 bits
|
||||
/// for width 3, and 3 bits for width 4.
|
||||
#[inline]
|
||||
fn utf8_first_byte(byte: u8, width: u32) -> u32 {
|
||||
const fn utf8_first_byte(byte: u8, width: u32) -> u32 {
|
||||
(byte & (0x7F >> width)) as u32
|
||||
}
|
||||
|
||||
/// Returns the value of `ch` updated with continuation byte `byte`.
|
||||
#[inline]
|
||||
fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 {
|
||||
const fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 {
|
||||
(ch << 6) | (byte & CONT_MASK) as u32
|
||||
}
|
||||
|
||||
/// Checks whether the byte is a UTF-8 continuation byte (i.e., starts with the
|
||||
/// bits `10`).
|
||||
#[inline]
|
||||
pub(super) fn utf8_is_cont_byte(byte: u8) -> bool {
|
||||
pub(super) const fn utf8_is_cont_byte(byte: u8) -> bool {
|
||||
(byte as i8) < -64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn unwrap_or_0(opt: Option<&u8>) -> u8 {
|
||||
const fn unwrap_or_0(opt: Option<&u8>) -> u8 {
|
||||
match opt {
|
||||
Some(&byte) => byte,
|
||||
None => 0,
|
||||
@ -105,14 +105,15 @@ const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize;
|
||||
|
||||
/// Returns `true` if any byte in the word `x` is nonascii (>= 128).
|
||||
#[inline]
|
||||
fn contains_nonascii(x: usize) -> bool {
|
||||
const fn contains_nonascii(x: usize) -> bool {
|
||||
(x & NONASCII_MASK) != 0
|
||||
}
|
||||
|
||||
/// Walks through `v` checking that it's a valid UTF-8 sequence,
|
||||
/// returning `Ok(())` in that case, or, if it is invalid, `Err(err)`.
|
||||
#[inline(always)]
|
||||
pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
|
||||
#[rustc_const_unstable(feature = "str_internals", issue = "none")]
|
||||
pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
|
||||
let mut index = 0;
|
||||
let len = v.len();
|
||||
|
||||
@ -142,7 +143,7 @@ pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
|
||||
|
||||
let first = v[index];
|
||||
if first >= 128 {
|
||||
let w = UTF8_CHAR_WIDTH[first as usize];
|
||||
let w = utf8_char_width(first);
|
||||
// 2-byte encoding is for codepoints \u{0080} to \u{07ff}
|
||||
// first C2 80 last DF BF
|
||||
// 3-byte encoding is for codepoints \u{0800} to \u{ffff}
|
||||
@ -230,7 +231,7 @@ pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc3629
|
||||
static UTF8_CHAR_WIDTH: [u8; 256] = [
|
||||
const UTF8_CHAR_WIDTH: &[u8; 256] = &[
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, // 0x1F
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
@ -253,7 +254,7 @@ static UTF8_CHAR_WIDTH: [u8; 256] = [
|
||||
#[unstable(feature = "str_internals", issue = "none")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn utf8_char_width(b: u8) -> usize {
|
||||
pub const fn utf8_char_width(b: u8) -> usize {
|
||||
UTF8_CHAR_WIDTH[b as usize] as usize
|
||||
}
|
||||
|
||||
|
@ -348,6 +348,18 @@ Using this flag looks like this:
|
||||
$ rustdoc src/lib.rs -Z unstable-options --show-coverage
|
||||
```
|
||||
|
||||
It generates something like this:
|
||||
|
||||
```bash
|
||||
+-------------------------------------+------------+------------+------------+------------+
|
||||
| File | Documented | Percentage | Examples | Percentage |
|
||||
+-------------------------------------+------------+------------+------------+------------+
|
||||
| lib.rs | 4 | 100.0% | 1 | 25.0% |
|
||||
+-------------------------------------+------------+------------+------------+------------+
|
||||
| Total | 4 | 100.0% | 1 | 25.0% |
|
||||
+-------------------------------------+------------+------------+------------+------------+
|
||||
```
|
||||
|
||||
If you want to determine how many items in your crate are documented, pass this flag to rustdoc.
|
||||
When it receives this flag, it will count the public items in your crate that have documentation,
|
||||
and print out the counts and a percentage instead of generating docs.
|
||||
@ -367,17 +379,25 @@ Some methodology notes about what rustdoc counts in this metric:
|
||||
Public items that are not documented can be seen with the built-in `missing_docs` lint. Private
|
||||
items that are not documented can be seen with Clippy's `missing_docs_in_private_items` lint.
|
||||
|
||||
### `-w`/`--output-format`: output format
|
||||
Calculating code examples follows these rules:
|
||||
|
||||
When using
|
||||
[`--show-coverage`](https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#--show-coverage-get-statistics-about-code-documentation-coverage),
|
||||
passing `--output-format json` will display the coverage information in JSON format. For example,
|
||||
here is the JSON for a file with one documented item and one undocumented item:
|
||||
1. These items aren't accounted by default:
|
||||
* struct/union field
|
||||
* enum variant
|
||||
* constant
|
||||
* static
|
||||
* typedef
|
||||
2. If one of the previously listed items has a code example, then it'll be counted.
|
||||
|
||||
#### JSON output
|
||||
|
||||
When using `--output-format json` with this option, it will display the coverage information in
|
||||
JSON format. For example, here is the JSON for a file with one documented item and one
|
||||
undocumented item:
|
||||
|
||||
```rust
|
||||
/// This item has documentation
|
||||
pub fn foo() {}
|
||||
|
||||
pub fn no_documentation() {}
|
||||
```
|
||||
|
||||
@ -387,10 +407,16 @@ pub fn no_documentation() {}
|
||||
|
||||
Note that the third item is the crate root, which in this case is undocumented.
|
||||
|
||||
When not using `--show-coverage`, `--output-format json` emits documentation in the experimental
|
||||
### `-w`/`--output-format`: output format
|
||||
|
||||
`--output-format json` emits documentation in the experimental
|
||||
[JSON format](https://github.com/rust-lang/rfcs/pull/2963). `--output-format html` has no effect,
|
||||
and is also accepted on stable toolchains.
|
||||
|
||||
It can also be used with `--show-coverage`. Take a look at its
|
||||
[documentation](#--show-coverage-get-statistics-about-code-documentation-coverage) for more
|
||||
information.
|
||||
|
||||
### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests
|
||||
|
||||
Using this flag looks like this:
|
||||
@ -441,39 +467,6 @@ $ rustdoc src/lib.rs -Z unstable-options --runtool valgrind
|
||||
|
||||
Another use case would be to run a test inside an emulator, or through a Virtual Machine.
|
||||
|
||||
### `--show-coverage`: get statistics about code documentation coverage
|
||||
|
||||
This option allows you to get a nice overview over your code documentation coverage, including both
|
||||
doc-comments and code examples in the doc-comments. Example:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z unstable-options --show-coverage
|
||||
+-------------------------------------+------------+------------+------------+------------+
|
||||
| File | Documented | Percentage | Examples | Percentage |
|
||||
+-------------------------------------+------------+------------+------------+------------+
|
||||
| lib.rs | 4 | 100.0% | 1 | 25.0% |
|
||||
+-------------------------------------+------------+------------+------------+------------+
|
||||
| Total | 4 | 100.0% | 1 | 25.0% |
|
||||
+-------------------------------------+------------+------------+------------+------------+
|
||||
```
|
||||
|
||||
You can also use this option with the `--output-format` one:
|
||||
|
||||
```bash
|
||||
$ rustdoc src/lib.rs -Z unstable-options --show-coverage --output-format json
|
||||
{"lib.rs":{"total":4,"with_docs":4,"total_examples":4,"with_examples":1}}
|
||||
```
|
||||
|
||||
Calculating code examples follows these rules:
|
||||
|
||||
1. These items aren't accounted by default:
|
||||
* struct/union field
|
||||
* enum variant
|
||||
* constant
|
||||
* static
|
||||
* typedef
|
||||
2. If one of the previously listed items has a code example, then it'll be counted.
|
||||
|
||||
### `--with-examples`: include examples of uses of items as documentation
|
||||
|
||||
This option, combined with `--scrape-examples-target-crate` and
|
||||
|
@ -229,6 +229,7 @@ fn build_external_function(cx: &mut DocContext<'_>, did: DefId) -> clean::Functi
|
||||
let asyncness = cx.tcx.asyncness(did);
|
||||
let predicates = cx.tcx.predicates_of(did);
|
||||
let (generics, decl) = clean::enter_impl_trait(cx, |cx| {
|
||||
// NOTE: generics need to be cleaned before the decl!
|
||||
((cx.tcx.generics_of(did), predicates).clean(cx), (did, sig).clean(cx))
|
||||
});
|
||||
clean::Function {
|
||||
|
@ -109,7 +109,10 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
|
||||
};
|
||||
|
||||
GenericBound::TraitBound(
|
||||
PolyTrait { trait_: (trait_ref, &*bindings).clean(cx), generic_params: vec![] },
|
||||
PolyTrait {
|
||||
trait_: (trait_ref, &bindings[..]).clean(cx),
|
||||
generic_params: vec![],
|
||||
},
|
||||
hir::TraitBoundModifier::None,
|
||||
)
|
||||
}
|
||||
@ -456,9 +459,7 @@ impl Clean<Generics> for hir::Generics<'_> {
|
||||
// scans them first.
|
||||
fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
|
||||
match param.kind {
|
||||
hir::GenericParamKind::Type { synthetic, .. } => {
|
||||
synthetic == Some(hir::SyntheticTyParamKind::ImplTrait)
|
||||
}
|
||||
hir::GenericParamKind::Type { synthetic, .. } => synthetic,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -557,7 +558,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, ty::GenericPredicates<'tcx
|
||||
assert_eq!(param.index, 0);
|
||||
return None;
|
||||
}
|
||||
if synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) {
|
||||
if synthetic {
|
||||
impl_trait.insert(param.index.into(), vec![]);
|
||||
return None;
|
||||
}
|
||||
@ -761,8 +762,13 @@ fn clean_fn_or_proc_macro(
|
||||
|
||||
impl<'a> Clean<Function> for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId) {
|
||||
fn clean(&self, cx: &mut DocContext<'_>) -> Function {
|
||||
let (generics, decl) =
|
||||
enter_impl_trait(cx, |cx| (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx)));
|
||||
let (generics, decl) = enter_impl_trait(cx, |cx| {
|
||||
// NOTE: generics must be cleaned before args
|
||||
let generics = self.1.clean(cx);
|
||||
let args = (self.0.decl.inputs, self.2).clean(cx);
|
||||
let decl = clean_fn_decl_with_args(cx, self.0.decl, args);
|
||||
(generics, decl)
|
||||
});
|
||||
Function { decl, generics, header: self.0.header }
|
||||
}
|
||||
}
|
||||
@ -804,17 +810,12 @@ impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], hir::BodyId) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl<'a>, A)
|
||||
where
|
||||
(&'a [hir::Ty<'a>], A): Clean<Arguments>,
|
||||
{
|
||||
fn clean(&self, cx: &mut DocContext<'_>) -> FnDecl {
|
||||
FnDecl {
|
||||
inputs: (self.0.inputs, self.1).clean(cx),
|
||||
output: self.0.output.clean(cx),
|
||||
c_variadic: self.0.c_variadic,
|
||||
}
|
||||
}
|
||||
fn clean_fn_decl_with_args(
|
||||
cx: &mut DocContext<'_>,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
args: Arguments,
|
||||
) -> FnDecl {
|
||||
FnDecl { inputs: args, output: decl.output.clean(cx), c_variadic: decl.c_variadic }
|
||||
}
|
||||
|
||||
impl<'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
|
||||
@ -894,7 +895,11 @@ impl Clean<Item> for hir::TraitItem<'_> {
|
||||
}
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
|
||||
let (generics, decl) = enter_impl_trait(cx, |cx| {
|
||||
(self.generics.clean(cx), (sig.decl, names).clean(cx))
|
||||
// NOTE: generics must be cleaned before args
|
||||
let generics = self.generics.clean(cx);
|
||||
let args = (sig.decl.inputs, names).clean(cx);
|
||||
let decl = clean_fn_decl_with_args(cx, sig.decl, args);
|
||||
(generics, decl)
|
||||
});
|
||||
let mut t = Function { header: sig.header, decl, generics };
|
||||
if t.header.constness == hir::Constness::Const
|
||||
@ -1727,8 +1732,10 @@ impl Clean<PathSegment> for hir::PathSegment<'_> {
|
||||
impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
|
||||
fn clean(&self, cx: &mut DocContext<'_>) -> BareFunctionDecl {
|
||||
let (generic_params, decl) = enter_impl_trait(cx, |cx| {
|
||||
// NOTE: generics must be cleaned before args
|
||||
let generic_params = self.generic_params.iter().map(|x| x.clean(cx)).collect();
|
||||
let decl = (self.decl, self.param_names).clean(cx);
|
||||
let args = (self.decl.inputs, self.param_names).clean(cx);
|
||||
let decl = clean_fn_decl_with_args(cx, self.decl, args);
|
||||
(generic_params, decl)
|
||||
});
|
||||
BareFunctionDecl { unsafety: self.unsafety, abi: self.abi, decl, generic_params }
|
||||
@ -2029,8 +2036,13 @@ impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
|
||||
let kind = match item.kind {
|
||||
hir::ForeignItemKind::Fn(decl, names, ref generics) => {
|
||||
let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
|
||||
let (generics, decl) =
|
||||
enter_impl_trait(cx, |cx| (generics.clean(cx), (decl, names).clean(cx)));
|
||||
let (generics, decl) = enter_impl_trait(cx, |cx| {
|
||||
// NOTE: generics must be cleaned before args
|
||||
let generics = generics.clean(cx);
|
||||
let args = (decl.inputs, names).clean(cx);
|
||||
let decl = clean_fn_decl_with_args(cx, decl, args);
|
||||
(generics, decl)
|
||||
});
|
||||
ForeignFunctionItem(Function {
|
||||
decl,
|
||||
generics,
|
||||
|
@ -1238,20 +1238,9 @@ impl WherePredicate {
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
crate enum GenericParamDefKind {
|
||||
Lifetime {
|
||||
outlives: Vec<Lifetime>,
|
||||
},
|
||||
Type {
|
||||
did: DefId,
|
||||
bounds: Vec<GenericBound>,
|
||||
default: Option<Box<Type>>,
|
||||
synthetic: Option<hir::SyntheticTyParamKind>,
|
||||
},
|
||||
Const {
|
||||
did: DefId,
|
||||
ty: Box<Type>,
|
||||
default: Option<Box<String>>,
|
||||
},
|
||||
Lifetime { outlives: Vec<Lifetime> },
|
||||
Type { did: DefId, bounds: Vec<GenericBound>, default: Option<Box<Type>>, synthetic: bool },
|
||||
Const { did: DefId, ty: Box<Type>, default: Option<Box<String>> },
|
||||
}
|
||||
|
||||
impl GenericParamDefKind {
|
||||
@ -1285,7 +1274,7 @@ impl GenericParamDef {
|
||||
crate fn is_synthetic_type_param(&self) -> bool {
|
||||
match self.kind {
|
||||
GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
|
||||
GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
|
||||
GenericParamDefKind::Type { synthetic, .. } => synthetic,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
// no-prefer-dynamic
|
||||
//[cfail1] compile-flags: -lbar -lfoo --crate-type lib
|
||||
//[cfail2] compile-flags: -lfoo -lbar --crate-type lib
|
||||
//[cfail1] compile-flags: -lbar -lfoo --crate-type lib -Zassert-incr-state=not-loaded
|
||||
//[cfail2] compile-flags: -lfoo -lbar --crate-type lib -Zassert-incr-state=not-loaded
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
// revisions:rpass1 cfail2
|
||||
// compile-flags: -Z query-dep-graph
|
||||
// [cfail2] compile-flags: -Z query-dep-graph -Z assert-incr-state=loaded
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
|
3
src/test/ui/suggestions/issue-90974.rs
Normal file
3
src/test/ui/suggestions/issue-90974.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
println!("{}", (3.).recip()); //~ERROR
|
||||
}
|
14
src/test/ui/suggestions/issue-90974.stderr
Normal file
14
src/test/ui/suggestions/issue-90974.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error[E0689]: can't call method `recip` on ambiguous numeric type `{float}`
|
||||
--> $DIR/issue-90974.rs:2:25
|
||||
|
|
||||
LL | println!("{}", (3.).recip());
|
||||
| ^^^^^
|
||||
|
|
||||
help: you must specify a concrete type for this numeric value, like `f32`
|
||||
|
|
||||
LL | println!("{}", (3_f32).recip());
|
||||
| ~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0689`.
|
@ -1,28 +0,0 @@
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
fn func<#[rustc_synthetic] T>(_: T) {}
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
pub fn func<#[rustc_synthetic] T>(_: T) {}
|
||||
}
|
||||
|
||||
struct Bar<S> {
|
||||
t: S
|
||||
}
|
||||
|
||||
impl<S> Bar<S> {
|
||||
pub fn func<#[rustc_synthetic] T>(_: T) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
func::<u8>(42); //~ ERROR cannot provide explicit generic arguments
|
||||
func(42); // Ok
|
||||
|
||||
Foo::func::<u8>(42); //~ ERROR cannot provide explicit generic arguments
|
||||
Foo::func(42); // Ok
|
||||
|
||||
Bar::<i8>::func::<u8>(42); //~ ERROR cannot provide explicit generic arguments
|
||||
Bar::<i8>::func(42); // Ok
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
|
||||
--> $DIR/synthetic-param.rs:20:12
|
||||
|
|
||||
LL | func::<u8>(42);
|
||||
| ^^ explicit generic argument not allowed
|
||||
|
|
||||
= note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
|
||||
= help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
|
||||
|
||||
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
|
||||
--> $DIR/synthetic-param.rs:23:17
|
||||
|
|
||||
LL | Foo::func::<u8>(42);
|
||||
| ^^ explicit generic argument not allowed
|
||||
|
|
||||
= note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
|
||||
= help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
|
||||
|
||||
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
|
||||
--> $DIR/synthetic-param.rs:26:23
|
||||
|
|
||||
LL | Bar::<i8>::func::<u8>(42);
|
||||
| ^^ explicit generic argument not allowed
|
||||
|
|
||||
= note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
|
||||
= help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0632`.
|
@ -3,10 +3,8 @@ use clippy_utils::source::snippet;
|
||||
use clippy_utils::{match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{
|
||||
self as hir, GenericArg, GenericBounds, GenericParamKind, HirId, Lifetime, MutTy, Mutability, Node, QPath,
|
||||
SyntheticTyParamKind, TyKind,
|
||||
};
|
||||
use rustc_hir::{self as hir, GenericArg, GenericBounds, GenericParamKind};
|
||||
use rustc_hir::{HirId, Lifetime, MutTy, Mutability, Node, QPath, TyKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use super::BORROWED_BOX;
|
||||
@ -105,7 +103,7 @@ fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id:
|
||||
if let Some(did) = cx.qpath_res(qpath, id).opt_def_id();
|
||||
if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
|
||||
if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
|
||||
if synthetic == Some(SyntheticTyParamKind::ImplTrait);
|
||||
if synthetic;
|
||||
then {
|
||||
Some(generic_param.bounds)
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user