Auto merge of #89449 - Manishearth:rollup-3alb61f, r=Manishearth
Rollup of 7 pull requests Successful merges: - #85223 (rustdoc: Clarified the attribute which prompts the warning) - #88847 (platform-support.md: correct ARMv7+MUSL platform triple notes) - #88963 (Coerce const FnDefs to implement const Fn traits ) - #89376 (Fix use after drop in self-profile with llvm events) - #89422 (Replace whitespaces in doctests' name with dashes) - #89440 (Clarify a sentence in the documentation of Vec (#84488)) - #89441 (Normalize after substituting via `field.ty()`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
@@ -406,13 +406,15 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let llvm_selfprofiler = if cgcx.prof.llvm_recording_enabled() {
|
let mut llvm_profiler = if cgcx.prof.llvm_recording_enabled() {
|
||||||
let mut llvm_profiler = LlvmSelfProfiler::new(cgcx.prof.get_self_profiler().unwrap());
|
Some(LlvmSelfProfiler::new(cgcx.prof.get_self_profiler().unwrap()))
|
||||||
&mut llvm_profiler as *mut _ as *mut c_void
|
|
||||||
} else {
|
} else {
|
||||||
std::ptr::null_mut()
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let llvm_selfprofiler =
|
||||||
|
llvm_profiler.as_mut().map(|s| s as *mut _ as *mut c_void).unwrap_or(std::ptr::null_mut());
|
||||||
|
|
||||||
let extra_passes = config.passes.join(",");
|
let extra_passes = config.passes.join(",");
|
||||||
|
|
||||||
// FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
|
// FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
|
||||||
|
|||||||
@@ -6,23 +6,6 @@ use rustc_middle::ty::TyCtxt;
|
|||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
/// Whether the `def_id` counts as const fn in your current crate, considering all active
|
|
||||||
/// feature gates
|
|
||||||
pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|
||||||
tcx.is_const_fn_raw(def_id)
|
|
||||||
&& match is_unstable_const_fn(tcx, def_id) {
|
|
||||||
Some(feature_name) => {
|
|
||||||
// has a `rustc_const_unstable` attribute, check whether the user enabled the
|
|
||||||
// corresponding feature gate.
|
|
||||||
tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name)
|
|
||||||
}
|
|
||||||
// functions without const stability are either stable user written
|
|
||||||
// const fn or the user is using feature gates and we thus don't
|
|
||||||
// care what they do
|
|
||||||
None => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
|
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
|
||||||
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
|
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
|
||||||
if tcx.is_const_fn_raw(def_id) {
|
if tcx.is_const_fn_raw(def_id) {
|
||||||
@@ -77,7 +60,7 @@ fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||||
is_const_fn(tcx, def_id)
|
tcx.is_const_fn(def_id)
|
||||||
&& match tcx.lookup_const_stability(def_id) {
|
&& match tcx.lookup_const_stability(def_id) {
|
||||||
Some(stab) => {
|
Some(stab) => {
|
||||||
if cfg!(debug_assertions) && stab.promotable {
|
if cfg!(debug_assertions) && stab.promotable {
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ use rustc_index::vec::{Idx, IndexVec};
|
|||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::{cmp, iter, mem};
|
use std::{cmp, iter, mem};
|
||||||
|
|
||||||
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
|
|
||||||
use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx};
|
use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx};
|
||||||
use crate::transform::MirPass;
|
use crate::transform::MirPass;
|
||||||
|
|
||||||
@@ -658,9 +657,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||||||
|
|
||||||
let is_const_fn = match *fn_ty.kind() {
|
let is_const_fn = match *fn_ty.kind() {
|
||||||
ty::FnDef(def_id, _) => {
|
ty::FnDef(def_id, _) => {
|
||||||
is_const_fn(self.tcx, def_id)
|
self.tcx.is_const_fn_raw(def_id) || is_lang_panic_fn(self.tcx, def_id)
|
||||||
|| is_unstable_const_fn(self.tcx, def_id).is_some()
|
|
||||||
|| is_lang_panic_fn(self.tcx, def_id)
|
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
@@ -1081,7 +1078,7 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>(
|
|||||||
if let ty::FnDef(def_id, _) = *literal.ty().kind() {
|
if let ty::FnDef(def_id, _) = *literal.ty().kind() {
|
||||||
if let Some((destination_place, _)) = destination {
|
if let Some((destination_place, _)) = destination {
|
||||||
if destination_place == place {
|
if destination_place == place {
|
||||||
if is_const_fn(ccx.tcx, def_id) {
|
if ccx.tcx.is_const_fn(def_id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,9 @@ pub enum SelectionCandidate<'tcx> {
|
|||||||
|
|
||||||
/// Implementation of a `Fn`-family trait by one of the anonymous
|
/// Implementation of a `Fn`-family trait by one of the anonymous
|
||||||
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
|
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
|
||||||
FnPointerCandidate,
|
FnPointerCandidate {
|
||||||
|
is_const: bool,
|
||||||
|
},
|
||||||
|
|
||||||
/// Builtin implementation of `DiscriminantKind`.
|
/// Builtin implementation of `DiscriminantKind`.
|
||||||
DiscriminantKindCandidate,
|
DiscriminantKindCandidate,
|
||||||
|
|||||||
@@ -2701,6 +2701,29 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
pub fn lifetime_scope(self, id: HirId) -> Option<LifetimeScopeForPath> {
|
pub fn lifetime_scope(self, id: HirId) -> Option<LifetimeScopeForPath> {
|
||||||
self.lifetime_scope_map(id.owner).and_then(|mut map| map.remove(&id.local_id))
|
self.lifetime_scope_map(id.owner).and_then(|mut map| map.remove(&id.local_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether the `def_id` counts as const fn in the current crate, considering all active
|
||||||
|
/// feature gates
|
||||||
|
pub fn is_const_fn(self, def_id: DefId) -> bool {
|
||||||
|
if self.is_const_fn_raw(def_id) {
|
||||||
|
match self.lookup_const_stability(def_id) {
|
||||||
|
Some(stability) if stability.level.is_unstable() => {
|
||||||
|
// has a `rustc_const_unstable` attribute, check whether the user enabled the
|
||||||
|
// corresponding feature gate.
|
||||||
|
self.features()
|
||||||
|
.declared_lib_features
|
||||||
|
.iter()
|
||||||
|
.any(|&(sym, _)| sym == stability.feature)
|
||||||
|
}
|
||||||
|
// functions without const stability are either stable user written
|
||||||
|
// const fn or the user is using feature gates and we thus don't
|
||||||
|
// care what they do
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TyCtxtAt<'tcx> {
|
impl TyCtxtAt<'tcx> {
|
||||||
|
|||||||
@@ -1638,8 +1638,8 @@ impl ReprOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> FieldDef {
|
impl<'tcx> FieldDef {
|
||||||
/// Returns the type of this field. The `subst` is typically obtained
|
/// Returns the type of this field. The resulting type is not normalized. The `subst` is
|
||||||
/// via the second field of `TyKind::AdtDef`.
|
/// typically obtained via the second field of `TyKind::AdtDef`.
|
||||||
pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
|
pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
|
||||||
tcx.type_of(self.did).subst(tcx, subst)
|
tcx.type_of(self.did).subst(tcx, subst)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1154,6 +1154,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
|
|||||||
|
|
||||||
variant.fields.iter().enumerate().filter_map(move |(i, field)| {
|
variant.fields.iter().enumerate().filter_map(move |(i, field)| {
|
||||||
let ty = field.ty(cx.tcx, substs);
|
let ty = field.ty(cx.tcx, substs);
|
||||||
|
// `field.ty()` doesn't normalize after substituting.
|
||||||
|
let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
|
||||||
let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
|
let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
|
||||||
let is_uninhabited = cx.is_uninhabited(ty);
|
let is_uninhabited = cx.is_uninhabited(ty);
|
||||||
|
|
||||||
@@ -1671,7 +1673,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
|
|||||||
write!(f, "{}", hi)
|
write!(f, "{}", hi)
|
||||||
}
|
}
|
||||||
IntRange(range) => write!(f, "{:?}", range), // Best-effort, will render e.g. `false` as `0..=0`
|
IntRange(range) => write!(f, "{:?}", range), // Best-effort, will render e.g. `false` as `0..=0`
|
||||||
Wildcard | Missing { .. } | NonExhaustive => write!(f, "_"),
|
Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty),
|
||||||
Or => {
|
Or => {
|
||||||
for pat in self.iter_fields() {
|
for pat in self.iter_fields() {
|
||||||
write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
|
write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
|
||||||
|
|||||||
@@ -781,8 +781,7 @@ fn is_useful<'p, 'tcx>(
|
|||||||
|
|
||||||
assert!(rows.iter().all(|r| r.len() == v.len()));
|
assert!(rows.iter().all(|r| r.len() == v.len()));
|
||||||
|
|
||||||
// FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
|
let ty = v.head().ty();
|
||||||
let ty = matrix.heads().next().map_or(v.head().ty(), |r| r.ty());
|
|
||||||
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
|
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
|
||||||
let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
|
let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
|
||||||
|
|
||||||
|
|||||||
@@ -476,7 +476,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
..
|
..
|
||||||
} = self_ty.fn_sig(self.tcx()).skip_binder()
|
} = self_ty.fn_sig(self.tcx()).skip_binder()
|
||||||
{
|
{
|
||||||
candidates.vec.push(FnPointerCandidate);
|
candidates.vec.push(FnPointerCandidate { is_const: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
|
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
|
||||||
@@ -489,7 +489,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
} = self_ty.fn_sig(self.tcx()).skip_binder()
|
} = self_ty.fn_sig(self.tcx()).skip_binder()
|
||||||
{
|
{
|
||||||
if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() {
|
if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() {
|
||||||
candidates.vec.push(FnPointerCandidate);
|
candidates
|
||||||
|
.vec
|
||||||
|
.push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
Ok(ImplSource::Generator(vtable_generator))
|
Ok(ImplSource::Generator(vtable_generator))
|
||||||
}
|
}
|
||||||
|
|
||||||
FnPointerCandidate => {
|
FnPointerCandidate { .. } => {
|
||||||
let data = self.confirm_fn_pointer_candidate(obligation)?;
|
let data = self.confirm_fn_pointer_candidate(obligation)?;
|
||||||
Ok(ImplSource::FnPointer(data))
|
Ok(ImplSource::FnPointer(data))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1112,6 +1112,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
// generator, this will raise error in other places
|
// generator, this will raise error in other places
|
||||||
// or ignore error with const_async_blocks feature
|
// or ignore error with const_async_blocks feature
|
||||||
GeneratorCandidate => {}
|
GeneratorCandidate => {}
|
||||||
|
// FnDef where the function is const
|
||||||
|
FnPointerCandidate { is_const: true } => {}
|
||||||
ConstDropCandidate => {}
|
ConstDropCandidate => {}
|
||||||
_ => {
|
_ => {
|
||||||
// reject all other types of candidates
|
// reject all other types of candidates
|
||||||
@@ -1539,6 +1541,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Drop otherwise equivalent non-const fn pointer candidates
|
||||||
|
(FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true,
|
||||||
|
|
||||||
// Global bounds from the where clause should be ignored
|
// Global bounds from the where clause should be ignored
|
||||||
// here (see issue #50825). Otherwise, we have a where
|
// here (see issue #50825). Otherwise, we have a where
|
||||||
// clause so don't go around looking for impls.
|
// clause so don't go around looking for impls.
|
||||||
@@ -1549,7 +1554,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
ImplCandidate(..)
|
ImplCandidate(..)
|
||||||
| ClosureCandidate
|
| ClosureCandidate
|
||||||
| GeneratorCandidate
|
| GeneratorCandidate
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate { .. }
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
| TraitUpcastingUnsizeCandidate(_)
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
@@ -1567,7 +1572,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
ImplCandidate(_)
|
ImplCandidate(_)
|
||||||
| ClosureCandidate
|
| ClosureCandidate
|
||||||
| GeneratorCandidate
|
| GeneratorCandidate
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate { .. }
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
| TraitUpcastingUnsizeCandidate(_)
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
@@ -1597,7 +1602,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
ImplCandidate(..)
|
ImplCandidate(..)
|
||||||
| ClosureCandidate
|
| ClosureCandidate
|
||||||
| GeneratorCandidate
|
| GeneratorCandidate
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate { .. }
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
| TraitUpcastingUnsizeCandidate(_)
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
@@ -1609,7 +1614,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
ImplCandidate(..)
|
ImplCandidate(..)
|
||||||
| ClosureCandidate
|
| ClosureCandidate
|
||||||
| GeneratorCandidate
|
| GeneratorCandidate
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate { .. }
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
| TraitUpcastingUnsizeCandidate(_)
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
@@ -1690,7 +1695,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
ImplCandidate(_)
|
ImplCandidate(_)
|
||||||
| ClosureCandidate
|
| ClosureCandidate
|
||||||
| GeneratorCandidate
|
| GeneratorCandidate
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate { .. }
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
| TraitUpcastingUnsizeCandidate(_)
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
@@ -1699,7 +1704,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
ImplCandidate(_)
|
ImplCandidate(_)
|
||||||
| ClosureCandidate
|
| ClosureCandidate
|
||||||
| GeneratorCandidate
|
| GeneratorCandidate
|
||||||
| FnPointerCandidate
|
| FnPointerCandidate { .. }
|
||||||
| BuiltinObjectCandidate
|
| BuiltinObjectCandidate
|
||||||
| BuiltinUnsizeCandidate
|
| BuiltinUnsizeCandidate
|
||||||
| TraitUpcastingUnsizeCandidate(_)
|
| TraitUpcastingUnsizeCandidate(_)
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ mod spec_extend;
|
|||||||
/// scratch space that it may use however it wants. It will generally just do
|
/// scratch space that it may use however it wants. It will generally just do
|
||||||
/// whatever is most efficient or otherwise easy to implement. Do not rely on
|
/// whatever is most efficient or otherwise easy to implement. Do not rely on
|
||||||
/// removed data to be erased for security purposes. Even if you drop a `Vec`, its
|
/// removed data to be erased for security purposes. Even if you drop a `Vec`, its
|
||||||
/// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory
|
/// buffer may simply be reused by another allocation. Even if you zero a `Vec`'s memory
|
||||||
/// first, that might not actually happen because the optimizer does not consider
|
/// first, that might not actually happen because the optimizer does not consider
|
||||||
/// this a side-effect that must be preserved. There is one case which we will
|
/// this a side-effect that must be preserved. There is one case which we will
|
||||||
/// not break, however: using `unsafe` code to write to the excess capacity,
|
/// not break, however: using `unsafe` code to write to the excess capacity,
|
||||||
|
|||||||
@@ -133,8 +133,8 @@ target | std | notes
|
|||||||
`armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL
|
`armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL
|
||||||
`armv7-linux-androideabi` | ✓ | ARMv7a Android
|
`armv7-linux-androideabi` | ✓ | ARMv7a Android
|
||||||
`armv7-unknown-linux-gnueabi` | ✓ |ARMv7 Linux (kernel 4.15, glibc 2.27)
|
`armv7-unknown-linux-gnueabi` | ✓ |ARMv7 Linux (kernel 4.15, glibc 2.27)
|
||||||
`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux, MUSL
|
`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux with MUSL
|
||||||
`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL
|
`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL, hardfloat
|
||||||
`armv7a-none-eabi` | * | Bare ARMv7-A
|
`armv7a-none-eabi` | * | Bare ARMv7-A
|
||||||
`armv7r-none-eabi` | * | Bare ARMv7-R
|
`armv7r-none-eabi` | * | Bare ARMv7-R
|
||||||
`armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat
|
`armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ This lint **warns by default**. This lint detects when [intra-doc links] from pu
|
|||||||
For example:
|
For example:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
#![warn(rustdoc::private_intra_doc_links)] // note: unecessary - warns by default.
|
||||||
|
|
||||||
/// [private]
|
/// [private]
|
||||||
pub fn public() {}
|
pub fn public() {}
|
||||||
fn private() {}
|
fn private() {}
|
||||||
@@ -227,6 +229,8 @@ This lint **warns by default**. It detects code block attributes in
|
|||||||
documentation examples that have potentially mis-typed values. For example:
|
documentation examples that have potentially mis-typed values. For example:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
#![warn(rustdoc::invalid_codeblock_attributes)] // note: unecessary - warns by default.
|
||||||
|
|
||||||
/// Example.
|
/// Example.
|
||||||
///
|
///
|
||||||
/// ```should-panic
|
/// ```should-panic
|
||||||
@@ -344,6 +348,8 @@ This lint is **warn-by-default**. It detects URLs which are not links.
|
|||||||
For example:
|
For example:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
#![warn(rustdoc::bare_urls)] // note: unecessary - warns by default.
|
||||||
|
|
||||||
/// http://example.org
|
/// http://example.org
|
||||||
/// [http://example.net]
|
/// [http://example.net]
|
||||||
pub fn foo() {}
|
pub fn foo() {}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ crate mod utils;
|
|||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
use rustc_const_eval::const_eval::{is_const_fn, is_unstable_const_fn};
|
use rustc_const_eval::const_eval::is_unstable_const_fn;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||||
@@ -787,7 +787,7 @@ fn clean_fn_or_proc_macro(
|
|||||||
let mut func = (sig, generics, body_id).clean(cx);
|
let mut func = (sig, generics, body_id).clean(cx);
|
||||||
let def_id = item.def_id.to_def_id();
|
let def_id = item.def_id.to_def_id();
|
||||||
func.header.constness =
|
func.header.constness =
|
||||||
if is_const_fn(cx.tcx, def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() {
|
if cx.tcx.is_const_fn(def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() {
|
||||||
hir::Constness::Const
|
hir::Constness::Const
|
||||||
} else {
|
} else {
|
||||||
hir::Constness::NotConst
|
hir::Constness::NotConst
|
||||||
|
|||||||
@@ -853,6 +853,7 @@ impl Collector {
|
|||||||
|
|
||||||
fn generate_name(&self, line: usize, filename: &FileName) -> String {
|
fn generate_name(&self, line: usize, filename: &FileName) -> String {
|
||||||
let mut item_path = self.names.join("::");
|
let mut item_path = self.names.join("::");
|
||||||
|
item_path.retain(|c| c != ' ');
|
||||||
if !item_path.is_empty() {
|
if !item_path.is_empty() {
|
||||||
item_path.push(' ');
|
item_path.push(' ');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
// From https://github.com/rust-lang/rust/issues/72476
|
||||||
|
// and https://github.com/rust-lang/rust/issues/89393
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct A;
|
||||||
|
impl Trait for A {
|
||||||
|
type Projection = bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct B;
|
||||||
|
impl Trait for B {
|
||||||
|
type Projection = (u32, u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Next<T: Trait>(T::Projection);
|
||||||
|
|
||||||
|
fn foo1(item: Next<A>) {
|
||||||
|
match item {
|
||||||
|
Next(true) => {}
|
||||||
|
Next(false) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo2(x: <A as Trait>::Projection) {
|
||||||
|
match x {
|
||||||
|
true => {}
|
||||||
|
false => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo3(x: Next<B>) {
|
||||||
|
let Next((_, _)) = x;
|
||||||
|
match x {
|
||||||
|
Next((_, _)) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo4(x: <B as Trait>::Projection) {
|
||||||
|
let (_, _) = x;
|
||||||
|
match x {
|
||||||
|
(_, _) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo5<T: Trait>(x: <T as Trait>::Projection) {
|
||||||
|
match x {
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// check-pass
|
|
||||||
|
|
||||||
// From https://github.com/rust-lang/rust/issues/72476
|
|
||||||
|
|
||||||
trait A {
|
|
||||||
type Projection;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl A for () {
|
|
||||||
type Projection = bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Next<T: A>(T::Projection);
|
|
||||||
|
|
||||||
fn f(item: Next<()>) {
|
|
||||||
match item {
|
|
||||||
Next(true) => {}
|
|
||||||
Next(false) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
||||||
31
src/test/ui/rfc-2632-const-trait-impl/const-closures.rs
Normal file
31
src/test/ui/rfc-2632-const-trait-impl/const-closures.rs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(const_trait_impl)]
|
||||||
|
#![feature(const_fn_trait_bound)]
|
||||||
|
|
||||||
|
const fn answer_p1<F>(f: &F) -> u8
|
||||||
|
where
|
||||||
|
F: ~const FnOnce() -> u8,
|
||||||
|
F: ~const FnMut() -> u8,
|
||||||
|
F: ~const Fn() -> u8,
|
||||||
|
{
|
||||||
|
f() * 7
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn three() -> u8 {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn answer_p2() -> u8 {
|
||||||
|
answer_p1(&three)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
|
||||||
|
f() + f()
|
||||||
|
}
|
||||||
|
|
||||||
|
const ANSWER: u8 = answer(&answer_p2);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(ANSWER, 42)
|
||||||
|
}
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
extern crate rustc_ast;
|
extern crate rustc_ast;
|
||||||
extern crate rustc_ast_pretty;
|
extern crate rustc_ast_pretty;
|
||||||
extern crate rustc_attr;
|
extern crate rustc_attr;
|
||||||
extern crate rustc_const_eval;
|
|
||||||
extern crate rustc_data_structures;
|
extern crate rustc_data_structures;
|
||||||
extern crate rustc_errors;
|
extern crate rustc_errors;
|
||||||
extern crate rustc_hir;
|
extern crate rustc_hir;
|
||||||
|
|||||||
@@ -364,7 +364,7 @@ fn check_terminator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> bool {
|
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> bool {
|
||||||
rustc_const_eval::const_eval::is_const_fn(tcx, def_id)
|
tcx.is_const_fn(def_id)
|
||||||
&& tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
|
&& tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
|
||||||
if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level {
|
if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level {
|
||||||
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire
|
// Checking MSRV is manually necessary because `rustc` has no such concept. This entire
|
||||||
|
|||||||
Reference in New Issue
Block a user