[[package]]
name = "compiler_builtins"
-version = "0.1.52"
+version = "0.1.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6591c2442ee984e2b264638a8b5e7ae44fd47b32d28e3a08e2e9c3cdb0c2fb0"
+checksum = "c9ac60765140c97aaf531dae151a287646b0805ec725805da9e2a3ee31cd501c"
dependencies = [
"cc",
"rustc-std-workspace-core",
[[package]]
name = "libc"
-version = "0.2.106"
+version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673"
+checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
dependencies = [
"rustc-std-workspace-core",
]
+Version 1.57.0 (2021-12-02)
+==========================
+
+Language
+--------
+
+- [Macro attributes may follow `#[derive]` and will see the original (pre-`cfg`) input.][87220]
+- [Accept curly-brace macros in expressions, like `m!{ .. }.method()` and `m!{ .. }?`.][88690]
+- [Allow panicking in constant evaluation.][89508]
+
+Compiler
+--------
+
+- [Create more accurate debuginfo for vtables.][89597]
+- [Add `armv6k-nintendo-3ds` at Tier 3\*.][88529]
+- [Add `armv7-unknown-linux-uclibceabihf` at Tier 3\*.][88952]
+- [Add `m68k-unknown-linux-gnu` at Tier 3\*.][88321]
+- [Add SOLID targets at Tier 3\*:][86191] `aarch64-kmc-solid_asp3`, `armv7a-kmc-solid_asp3-eabi`, `armv7a-kmc-solid_asp3-eabihf`
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+ information on Rust's tiered platform support.
+
+Libraries
+---------
+
+- [Avoid allocations and copying in `Vec::leak`][89337]
+- [Add `#[repr(i8)]` to `Ordering`][89507]
+- [Optimize `File::read_to_end` and `read_to_string`][89582]
+- [Update to Unicode 14.0][89614]
+- [Many more functions are marked `#[must_use]`][89692], producing a warning
+ when ignoring their return value. This helps catch mistakes such as expecting
+ a function to mutate a value in place rather than return a new value.
+
+Stabilised APIs
+---------------
+
+- [`[T; N]::as_mut_slice`][`array::as_mut_slice`]
+- [`[T; N]::as_slice`][`array::as_slice`]
+- [`collections::TryReserveError`]
+- [`HashMap::try_reserve`]
+- [`HashSet::try_reserve`]
+- [`String::try_reserve`]
+- [`String::try_reserve_exact`]
+- [`Vec::try_reserve`]
+- [`Vec::try_reserve_exact`]
+- [`VecDeque::try_reserve`]
+- [`VecDeque::try_reserve_exact`]
+- [`Iterator::map_while`]
+- [`iter::MapWhile`]
+- [`proc_macro::is_available`]
+- [`Command::get_program`]
+- [`Command::get_args`]
+- [`Command::get_envs`]
+- [`Command::get_current_dir`]
+- [`CommandArgs`]
+- [`CommandEnvs`]
+
+These APIs are now usable in const contexts:
+
+- [`hint::unreachable_unchecked`]
+
+Cargo
+-----
+
+- [Stabilize custom profiles][cargo/9943]
+
+Compatibility notes
+-------------------
+
+Internal changes
+----------------
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc
+and related tools.
+
+- [Added an experimental backend for codegen with `libgccjit`.][87260]
+
+[86191]: https://github.com/rust-lang/rust/pull/86191/
+[87220]: https://github.com/rust-lang/rust/pull/87220/
+[87260]: https://github.com/rust-lang/rust/pull/87260/
+[88243]: https://github.com/rust-lang/rust/pull/88243/
+[88321]: https://github.com/rust-lang/rust/pull/88321/
+[88529]: https://github.com/rust-lang/rust/pull/88529/
+[88690]: https://github.com/rust-lang/rust/pull/88690/
+[88952]: https://github.com/rust-lang/rust/pull/88952/
+[89337]: https://github.com/rust-lang/rust/pull/89337/
+[89507]: https://github.com/rust-lang/rust/pull/89507/
+[89508]: https://github.com/rust-lang/rust/pull/89508/
+[89582]: https://github.com/rust-lang/rust/pull/89582/
+[89597]: https://github.com/rust-lang/rust/pull/89597/
+[89614]: https://github.com/rust-lang/rust/pull/89614/
+[89692]: https://github.com/rust-lang/rust/issues/89692/
+[cargo/9943]: https://github.com/rust-lang/cargo/pull/9943/
+[`array::as_mut_slice`]: https://doc.rust-lang.org/std/primitive.array.html#method.as_mut_slice
+[`array::as_slice`]: https://doc.rust-lang.org/std/primitive.array.html#method.as_slice
+[`collections::TryReserveError`]: https://doc.rust-lang.org/std/collections/struct.TryReserveError.html
+[`HashMap::try_reserve`]: https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.try_reserve
+[`HashSet::try_reserve`]: https://doc.rust-lang.org/std/collections/hash_set/struct.HashSet.html#method.try_reserve
+[`String::try_reserve`]: https://doc.rust-lang.org/alloc/string/struct.String.html#method.try_reserve
+[`String::try_reserve_exact`]: https://doc.rust-lang.org/alloc/string/struct.String.html#method.try_reserve_exact
+[`Vec::try_reserve`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.try_reserve
+[`Vec::try_reserve_exact`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.try_reserve_exact
+[`VecDeque::try_reserve`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.try_reserve
+[`VecDeque::try_reserve_exact`]: https://doc.rust-lang.org/std/collections/struct.VecDeque.html#method.try_reserve_exact
+[`Iterator::map_while`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map_while
+[`iter::MapWhile`]: https://doc.rust-lang.org/std/iter/struct.MapWhile.html
+[`proc_macro::is_available`]: https://doc.rust-lang.org/proc_macro/fn.is_available.html
+[`Command::get_program`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_program
+[`Command::get_args`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_args
+[`Command::get_envs`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_envs
+[`Command::get_current_dir`]: https://doc.rust-lang.org/std/process/struct.Command.html#method.get_current_dir
+[`CommandArgs`]: https://doc.rust-lang.org/std/process/struct.CommandArgs.html
+[`CommandEnvs`]: https://doc.rust-lang.org/std/process/struct.CommandEnvs.html
+
Version 1.56.1 (2021-11-01)
===========================
use rustc_span::Span;
use rustc_target::spec::abi;
use std::mem;
-use std::ops::DerefMut;
+use std::ops::{Deref, DerefMut};
const MORE_EXTERN: &str =
"for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
}
}
}
+ // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
+ if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind {
+ if let [potential_param, potential_assoc] = &full_path.segments[..] {
+ for param in &generics.params {
+ if param.ident == potential_param.ident {
+ for bound in ¶m.bounds {
+ if let ast::GenericBound::Trait(trait_ref, TraitBoundModifier::None) = bound
+ {
+ if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] {
+ let assoc = pprust::path_to_string(&ast::Path::from_ident(
+ potential_assoc.ident,
+ ));
+ let ty = pprust::ty_to_string(&predicate.rhs_ty);
+ let (args, span) = match &trait_segment.args {
+ Some(args) => match args.deref() {
+ ast::GenericArgs::AngleBracketed(args) => {
+ let Some(arg) = args.args.last() else {
+ continue;
+ };
+ (
+ format!(", {} = {}", assoc, ty),
+ arg.span().shrink_to_hi(),
+ )
+ }
+ _ => continue,
+ },
+ None => (
+ format!("<{} = {}>", assoc, ty),
+ trait_segment.span().shrink_to_hi(),
+ ),
+ };
+ err.multipart_suggestion(
+ &format!(
+ "if `{}::{}` is an associated type you're trying to set, \
+ use the associated type binding syntax",
+ trait_segment.ident, potential_assoc.ident,
+ ),
+ vec![(span, args), (predicate.span, String::new())],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
err.note(
"see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information",
);
#![feature(iter_is_partitioned)]
#![feature(box_patterns)]
+#![feature(let_else)]
#![recursion_limit = "256"]
pub mod ast_validation;
BorrowedContentSource::DerefRawPointer => "a raw pointer".to_string(),
BorrowedContentSource::DerefSharedRef => "a shared reference".to_string(),
BorrowedContentSource::DerefMutableRef => "a mutable reference".to_string(),
- BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
- "an `Rc`".to_string()
- }
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
- "an `Arc`".to_string()
- }
- _ => format!("dereference of `{}`", ty),
- },
+ BorrowedContentSource::OverloadedDeref(ty) => ty
+ .ty_adt_def()
+ .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
+ name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+ _ => None,
+ })
+ .unwrap_or_else(|| format!("dereference of `{}`", ty)),
BorrowedContentSource::OverloadedIndex(ty) => format!("index of `{}`", ty),
}
}
BorrowedContentSource::DerefMutableRef => {
bug!("describe_for_immutable_place: DerefMutableRef isn't immutable")
}
- BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() {
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => {
- "an `Rc`".to_string()
- }
- ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Arc, def.did) => {
- "an `Arc`".to_string()
- }
- _ => format!("a dereference of `{}`", ty),
- },
+ BorrowedContentSource::OverloadedDeref(ty) => ty
+ .ty_adt_def()
+ .and_then(|adt| match tcx.get_diagnostic_name(adt.did)? {
+ name @ (sym::Rc | sym::Arc) => Some(format!("an `{}`", name)),
+ _ => None,
+ })
+ .unwrap_or_else(|| format!("dereference of `{}`", ty)),
BorrowedContentSource::OverloadedIndex(ty) => format!("an index of `{}`", ty),
}
}
_ => None,
});
let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
- tcx.is_diagnostic_item(sym::Option, def_id)
- || tcx.is_diagnostic_item(sym::Result, def_id)
+ matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
});
FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
});
use rustc_index::vec::IndexVec;
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::mir::visit::{MutVisitor, TyContext};
-use rustc_middle::mir::{Body, Location, PlaceElem, Promoted};
+use rustc_middle::mir::{Body, Location, Promoted};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
debug!(?ty);
}
- fn process_projection_elem(
- &mut self,
- elem: PlaceElem<'tcx>,
- _: Location,
- ) -> Option<PlaceElem<'tcx>> {
- if let PlaceElem::Field(field, ty) = elem {
- let new_ty = self.renumber_regions(ty);
-
- if new_ty != ty {
- return Some(PlaceElem::Field(field, new_ty));
- }
- }
-
- None
- }
-
#[instrument(skip(self), level = "debug")]
fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
*substs = self.renumber_regions(*substs);
debug!("build: input_or_output={:?}", ty);
// We add implied bounds from both the unnormalized and normalized ty
// See issue #87748
- let constraints_implied_1 = self.add_implied_bounds(ty);
let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
// }
// ```
// Both &Self::Bar and &() are WF
- let constraints_implied_2 =
- if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
+ let constraints_implied = self.add_implied_bounds(norm_ty);
normalized_inputs_and_output.push(norm_ty);
- constraints1.into_iter().chain(constraints_implied_1).chain(constraints_implied_2)
+ constraints1.into_iter().chain(constraints_implied)
})
.collect();
use rustc_expand::config::StripUnconfigured;
use rustc_expand::configure;
use rustc_feature::Features;
-use rustc_parse::parser::ForceCollect;
+use rustc_parse::parser::{ForceCollect, Parser};
use rustc_session::utils::FlattenNonterminals;
use rustc_session::Session;
use rustc_span::symbol::sym;
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
// process is lossless, so this process is invisible to proc-macros.
- // FIXME - get rid of this clone
- let nt = annotatable.clone().into_nonterminal();
+ let parse_annotatable_with: fn(&mut Parser<'_>) -> _ = match annotatable {
+ Annotatable::Item(_) => {
+ |parser| Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
+ }
+ Annotatable::TraitItem(_) => |parser| {
+ Annotatable::TraitItem(
+ parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+ )
+ },
+ Annotatable::ImplItem(_) => |parser| {
+ Annotatable::ImplItem(
+ parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+ )
+ },
+ Annotatable::ForeignItem(_) => |parser| {
+ Annotatable::ForeignItem(
+ parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
+ )
+ },
+ Annotatable::Stmt(_) => |parser| {
+ Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
+ },
+ Annotatable::Expr(_) => {
+ |parser| Annotatable::Expr(parser.parse_expr_force_collect().unwrap())
+ }
+ _ => unreachable!(),
+ };
+ let nt = annotatable.into_nonterminal();
let mut orig_tokens = rustc_parse::nt_to_tokenstream(
&nt,
let mut parser =
rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
parser.capture_cfg = true;
- annotatable = match annotatable {
- Annotatable::Item(_) => {
- Annotatable::Item(parser.parse_item(ForceCollect::Yes).unwrap().unwrap())
- }
- Annotatable::TraitItem(_) => Annotatable::TraitItem(
- parser.parse_trait_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- ),
- Annotatable::ImplItem(_) => Annotatable::ImplItem(
- parser.parse_impl_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- ),
- Annotatable::ForeignItem(_) => Annotatable::ForeignItem(
- parser.parse_foreign_item(ForceCollect::Yes).unwrap().unwrap().unwrap(),
- ),
- Annotatable::Stmt(_) => {
- Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes).unwrap().unwrap()))
- }
- Annotatable::Expr(_) => Annotatable::Expr(parser.parse_expr_force_collect().unwrap()),
- _ => unreachable!(),
- };
+ annotatable = parse_annotatable_with(&mut parser);
// Now that we have our re-parsed `AttrAnnotatedTokenStream`, recursively configuring
// our attribute target will correctly the tokens as well.
/// * Implicit argument resolution: `"{1:.0$} {2:.foo$} {1:.3$} {4:.0$}"`
/// * Name resolution: `"{1:.0$} {2:.5$} {1:.3$} {4:.0$}"`
/// * `count_positions` (in JSON): `{0: 0, 5: 1, 3: 2}`
- /// * `count_args`: `vec![Exact(0), Exact(5), Exact(3)]`
- count_args: Vec<Position>,
+ /// * `count_args`: `vec![0, 5, 3]`
+ count_args: Vec<usize>,
/// Relative slot numbers for count arguments.
count_positions: FxHashMap<usize, usize>,
/// Number of count slots assigned.
if let Entry::Vacant(e) = self.count_positions.entry(arg) {
let i = self.count_positions_count;
e.insert(i);
- self.count_args.push(Exact(arg));
+ self.count_args.push(arg);
self.count_positions_count += 1;
}
}
for arg_ty in self.arg_unique_types[i].iter() {
args.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, i));
}
- heads.push(self.ecx.expr_addr_of(e.span, e));
+ // use the arg span for `&arg` so that borrowck errors
+ // point to the specific expression passed to the macro
+ // (the span is otherwise unavailable in MIR)
+ heads.push(self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e));
}
- for pos in self.count_args {
- let index = match pos {
- Exact(i) => i,
- _ => panic!("should never happen"),
- };
+ for index in self.count_args {
let span = spans_pos[index];
args.push(Context::format_arg(self.ecx, self.macsp, span, &Count, index));
}
pub struct DiagnosticHandlers<'a> {
data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a Handler),
llcx: &'a llvm::Context,
+ old_handler: Option<&'a llvm::DiagnosticHandler>,
}
impl<'a> DiagnosticHandlers<'a> {
handler: &'a Handler,
llcx: &'a llvm::Context,
) -> Self {
+ let remark_passes_all: bool;
+ let remark_passes: Vec<CString>;
+ match &cgcx.remark {
+ Passes::All => {
+ remark_passes_all = true;
+ remark_passes = Vec::new();
+ }
+ Passes::Some(passes) => {
+ remark_passes_all = false;
+ remark_passes =
+ passes.iter().map(|name| CString::new(name.as_str()).unwrap()).collect();
+ }
+ };
+ let remark_passes: Vec<*const c_char> =
+ remark_passes.iter().map(|name: &CString| name.as_ptr()).collect();
let data = Box::into_raw(Box::new((cgcx, handler)));
unsafe {
+ let old_handler = llvm::LLVMRustContextGetDiagnosticHandler(llcx);
+ llvm::LLVMRustContextConfigureDiagnosticHandler(
+ llcx,
+ diagnostic_handler,
+ data.cast(),
+ remark_passes_all,
+ remark_passes.as_ptr(),
+ remark_passes.len(),
+ );
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data.cast());
- llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data.cast());
+ DiagnosticHandlers { data, llcx, old_handler }
}
- DiagnosticHandlers { data, llcx }
}
}
use std::ptr::null_mut;
unsafe {
llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, null_mut());
- llvm::LLVMContextSetDiagnosticHandler(self.llcx, diagnostic_handler, null_mut());
+ llvm::LLVMRustContextSetDiagnosticHandler(self.llcx, self.old_handler);
drop(Box::from_raw(self.data));
}
}
if enabled {
diag_handler.note_without_error(&format!(
- "optimization {} for {} at {}:{}:{}: {}",
- opt.kind.describe(),
- opt.pass_name,
- opt.filename,
- opt.line,
- opt.column,
- opt.message
+ "{}:{}:{}: {}: {}",
+ opt.filename, opt.line, opt.column, opt.pass_name, opt.message,
));
}
}
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_llvm::RustString;
use rustc_middle::mir::coverage::CodeRegion;
+use rustc_middle::ty::TyCtxt;
use rustc_span::Symbol;
use std::ffi::CString;
/// Generates and exports the Coverage Map.
///
-/// This Coverage Map complies with Coverage Mapping Format version 4 (zero-based encoded as 3),
-/// as defined at [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format)
-/// and published in Rust's November 2020 fork of LLVM. This version is supported by the LLVM
-/// coverage tools (`llvm-profdata` and `llvm-cov`) bundled with Rust's fork of LLVM.
+/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions
+/// 5 (LLVM 12, only) and 6 (zero-based encoded as 4 and 5, respectively), as defined at
+/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
+/// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`)
+/// bundled with Rust's fork of LLVM.
///
/// Consequently, Rust's bundled version of Clang also generates Coverage Maps compliant with
/// the same version. Clang's implementation of Coverage Map generation was referenced when
pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
let tcx = cx.tcx;
- // Ensure LLVM supports Coverage Map Version 4 (encoded as a zero-based value: 3).
- // If not, the LLVM Version must be less than 11.
+ // Ensure the installed version of LLVM supports at least Coverage Map
+ // Version 5 (encoded as a zero-based value: 4), which was introduced with
+ // LLVM 12.
let version = coverageinfo::mapping_version();
- if version != 3 {
- tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 11 or higher.");
+ if version < 4 {
+ tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 12 or higher.");
}
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
return;
}
- let mut mapgen = CoverageMapGenerator::new();
+ let mut mapgen = CoverageMapGenerator::new(tcx, version);
// Encode coverage mappings and generate function records
let mut function_data = Vec::new();
}
impl CoverageMapGenerator {
- fn new() -> Self {
- Self { filenames: FxIndexSet::default() }
+ fn new(tcx: TyCtxt<'_>, version: u32) -> Self {
+ let mut filenames = FxIndexSet::default();
+ if version >= 5 {
+ // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
+ // requires setting the first filename to the compilation directory.
+ // Since rustc generates coverage maps with relative paths, the
+ // compilation directory can be combined with the the relative paths
+ // to get absolute paths, if needed.
+ let working_dir = tcx
+ .sess
+ .opts
+ .working_dir
+ .remapped_path_if_available()
+ .to_string_lossy()
+ .to_string();
+ let c_filename =
+ CString::new(working_dir).expect("null error converting filename to C string");
+ filenames.insert(c_filename);
+ }
+ Self { filenames }
}
/// Using the `expressions` and `counter_regions` collected for the current function, generate
#[repr(C)]
pub struct Linker<'a>(InvariantOpaque<'a>);
-pub type DiagnosticHandler = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
-pub type InlineAsmDiagHandler = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
+extern "C" {
+ pub type DiagnosticHandler;
+}
+
+pub type DiagnosticHandlerTy = unsafe extern "C" fn(&DiagnosticInfo, *mut c_void);
+pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_void, c_uint);
pub mod coverageinfo {
use super::coverage_map;
- /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222)
+ /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L209-L230)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum RegionKind {
/// A GapRegion is like a CodeRegion, but its count is only set as the
/// line execution count when its the only region in the line.
GapRegion = 3,
+
+ /// A BranchRegion represents leaf-level boolean expressions and is
+ /// associated with two counters, each representing the number of times the
+ /// expression evaluates to true or false.
+ BranchRegion = 4,
}
/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
/// coverage map, in accordance with the
- /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
+ /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
/// The struct composes fields representing the `Counter` type and value(s) (injected counter
/// ID, or expression type and operands), the source file (an indirect index into a "filenames
/// array", encoded separately), and source location (start and end positions of the represented
/// The counter type and type-dependent counter data, if any.
counter: coverage_map::Counter,
+ /// If the `RegionKind` is a `BranchRegion`, this represents the counter
+ /// for the false branch of the region.
+ false_counter: coverage_map::Counter,
+
/// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
/// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
/// that, in turn, are used to look up the filename for this region.
) -> Self {
Self {
counter,
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id: 0,
start_line,
}
}
+ // This function might be used in the future; the LLVM API is still evolving, as is coverage
+ // support.
+ #[allow(dead_code)]
+ crate fn branch_region(
+ counter: coverage_map::Counter,
+ false_counter: coverage_map::Counter,
+ file_id: u32,
+ start_line: u32,
+ start_col: u32,
+ end_line: u32,
+ end_col: u32,
+ ) -> Self {
+ Self {
+ counter,
+ false_counter,
+ file_id,
+ expanded_file_id: 0,
+ start_line,
+ start_col,
+ end_line,
+ end_col,
+ kind: RegionKind::BranchRegion,
+ }
+ }
+
// This function might be used in the future; the LLVM API is still evolving, as is coverage
// support.
#[allow(dead_code)]
) -> Self {
Self {
counter: coverage_map::Counter::zero(),
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id,
start_line,
) -> Self {
Self {
counter: coverage_map::Counter::zero(),
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id: 0,
start_line,
) -> Self {
Self {
counter,
+ false_counter: coverage_map::Counter::zero(),
file_id,
expanded_file_id: 0,
start_line,
#[allow(improper_ctypes)]
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
- pub fn LLVMContextSetDiagnosticHandler(
- C: &Context,
- Handler: DiagnosticHandler,
- DiagnosticContext: *mut c_void,
- );
-
#[allow(improper_ctypes)]
pub fn LLVMRustUnpackOptimizationDiagnostic(
DI: &'a DiagnosticInfo,
pub fn LLVMRustSetInlineAsmDiagnosticHandler(
C: &Context,
- H: InlineAsmDiagHandler,
+ H: InlineAsmDiagHandlerTy,
CX: *mut c_void,
);
mod_id: *const c_char,
data: &ThinLTOData,
);
+
+ pub fn LLVMRustContextGetDiagnosticHandler(Context: &Context) -> Option<&DiagnosticHandler>;
+ pub fn LLVMRustContextSetDiagnosticHandler(
+ context: &Context,
+ diagnostic_handler: Option<&DiagnosticHandler>,
+ );
+ pub fn LLVMRustContextConfigureDiagnosticHandler(
+ context: &Context,
+ diagnostic_handler_callback: DiagnosticHandlerTy,
+ diagnostic_handler_context: *mut c_void,
+ remark_all_passes: bool,
+ remark_passes: *const *const c_char,
+ remark_passes_len: usize,
+ );
+
}
use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex};
-/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L206-L222)
+/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L95)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum CounterKind {
/// `instrprof.increment()`)
/// * For `CounterKind::Expression`, `id` is the index into the coverage map's array of
/// counter expressions.
-/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L99-L100)
+/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L102-L103)
/// Important: The Rust struct layout (order and types of fields) must match its C++ counterpart.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
}
}
-/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L147)
+/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L150)
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum ExprKind {
Add = 1,
}
-/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L148-L149)
+/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L151-L152)
/// Important: The Rust struct layout (order and types of fields) must match its C++
/// counterpart.
#[derive(Copy, Clone, Debug)]
sym::transmute => {
self.copy_op_transmute(&args[0], dest)?;
}
- sym::assert_inhabited => {
+ sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
let ty = instance.substs.type_at(0);
let layout = self.layout_of(ty)?;
+ // For *all* intrinsics we first check `is_uninhabited` to give a more specific
+ // error message.
if layout.abi.is_uninhabited() {
// The run-time intrinsic panics just to get a good backtrace; here we abort
// since there is no problem showing a backtrace even for aborts.
),
)?;
}
+ if intrinsic_name == sym::assert_zero_valid
+ && !layout.might_permit_raw_init(self, /*zero:*/ true)
+ {
+ M::abort(
+ self,
+ format!(
+ "aborted execution: attempted to zero-initialize type `{}`, which is invalid",
+ ty
+ ),
+ )?;
+ }
+ if intrinsic_name == sym::assert_uninit_valid
+ && !layout.might_permit_raw_init(self, /*zero:*/ false)
+ {
+ M::abort(
+ self,
+ format!(
+ "aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
+ ty
+ ),
+ )?;
+ }
}
sym::simd_insert => {
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
let elem_size = first.layout.size;
let first_ptr = first.ptr;
let rest_ptr = first_ptr.offset(elem_size, self)?;
+ // For the alignment of `rest_ptr`, we crucially do *not* use `first.align` as
+ // that place might be more aligned than its type mandates (a `u8` array could
+ // be 4-aligned if it sits at the right spot in a struct). Instead we use
+ // `first.layout.align`, i.e., the alignment given by the type.
self.memory.copy_repeatedly(
first_ptr,
first.align,
rest_ptr,
- first.align,
+ first.layout.align.abi,
elem_size,
length - 1,
/*nonoverlapping:*/ true,
#![feature(trusted_len)]
#![feature(trusted_step)]
#![feature(try_blocks)]
+#![feature(unwrap_infallible)]
#![recursion_limit = "256"]
#[macro_use]
//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
use rustc_errors::{Applicability, Diagnostic, ErrorReported};
+use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_hir::{self as hir, HirId, LangItem};
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
-use rustc_trait_selection::traits::{self, SelectionContext, TraitEngine};
+use rustc_trait_selection::traits::SelectionContext;
use std::mem;
use std::ops::Deref;
self.visit_body(&body);
}
- // Ensure that the end result is `Sync` in a non-thread local `static`.
- let should_check_for_sync = self.const_kind()
- == hir::ConstContext::Static(hir::Mutability::Not)
- && !tcx.is_thread_local_static(def_id.to_def_id());
-
- if should_check_for_sync {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- check_return_ty_is_sync(tcx, &body, hir_id);
- }
-
// If we got through const-checking without emitting any "primary" errors, emit any
// "secondary" errors if they occurred.
let secondary_errors = mem::take(&mut self.secondary_errors);
}
}
-fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId) {
- let ty = body.return_ty();
- tcx.infer_ctxt().enter(|infcx| {
- let cause = traits::ObligationCause::new(body.span, hir_id, traits::SharedStatic);
- let mut fulfillment_cx = traits::FulfillmentContext::new();
- let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span));
- fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
- let errors = fulfillment_cx.select_all_or_error(&infcx);
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
- });
-}
-
fn place_as_reborrow(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
pub mod check_consts;
pub mod promote_consts;
pub mod validate;
-
-pub use rustc_middle::mir::MirPass;
use std::{cmp, iter, mem};
use crate::transform::check_consts::{qualifs, ConstCx};
-use crate::transform::MirPass;
/// A `MirPass` for promotion.
///
//! Validates the MIR to ensure that invariants are upheld.
-use super::MirPass;
use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::traversal;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{
- AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem,
- PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+ AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPass, MirPhase, Operand,
+ PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
TerminatorKind, START_BLOCK,
};
use rustc_middle::ty::fold::BottomUpFolder;
// Leave consts and types unchanged.
ct_op: |ct| ct,
ty_op: |ty| ty,
- }),
+ })
+ .into_ok(),
)
};
tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok())
use rustc_index::vec::{Idx, IndexVec};
use std::mem;
-use std::ptr;
-pub trait IdFunctor {
+pub trait IdFunctor: Sized {
type Inner;
- fn map_id<F>(self, f: F) -> Self
+ #[inline]
+ fn map_id<F>(self, mut f: F) -> Self
+ where
+ F: FnMut(Self::Inner) -> Self::Inner,
+ {
+ self.try_map_id::<_, !>(|value| Ok(f(value))).into_ok()
+ }
+
+ fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner;
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>;
}
impl<T> IdFunctor for Box<T> {
type Inner = T;
#[inline]
- fn map_id<F>(self, mut f: F) -> Self
+ fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
let raw = Box::into_raw(self);
- unsafe {
+ Ok(unsafe {
// SAFETY: The raw pointer points to a valid value of type `T`.
- let value = ptr::read(raw);
+ let value = raw.read();
// SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
// inverse of `Box::assume_init()` and should be safe.
let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
// SAFETY: Write the mapped value back into the `Box`.
- raw.write(f(value));
+ raw.write(f(value)?);
// SAFETY: We just initialized `raw`.
raw.assume_init()
- }
+ })
}
}
type Inner = T;
#[inline]
- fn map_id<F>(mut self, mut f: F) -> Self
+ fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
// FIXME: We don't really care about panics here and leak
// far more than we should, but that should be fine for now.
let start = self.as_mut_ptr();
for i in 0..len {
let p = start.add(i);
- ptr::write(p, f(ptr::read(p)));
+ match f(p.read()) {
+ Ok(val) => p.write(val),
+ Err(err) => {
+ // drop all other elements in self
+ // (current element was "moved" into the call to f)
+ for j in (0..i).chain(i + 1..len) {
+ start.add(j).drop_in_place();
+ }
+
+ // returning will drop self, releasing the allocation
+ // (len is 0 so elements will not be re-dropped)
+ return Err(err);
+ }
+ }
}
+ // Even if we encountered an error, set the len back
+ // so we don't leak memory.
self.set_len(len);
}
- self
+ Ok(self)
}
}
type Inner = T;
#[inline]
- fn map_id<F>(self, f: F) -> Self
+ fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
- Vec::from(self).map_id(f).into()
+ Vec::from(self).try_map_id(f).map(Into::into)
}
}
type Inner = T;
#[inline]
- fn map_id<F>(self, f: F) -> Self
+ fn try_map_id<F, E>(self, f: F) -> Result<Self, E>
where
- F: FnMut(Self::Inner) -> Self::Inner,
+ F: FnMut(Self::Inner) -> Result<Self::Inner, E>,
{
- IndexVec::from_raw(self.raw.map_id(f))
+ self.raw.try_map_id(f).map(IndexVec::from_raw)
}
}
#![feature(once_cell)]
#![feature(test)]
#![feature(thread_id_value)]
+#![feature(unwrap_infallible)]
#![allow(rustc::default_hash_types)]
#![deny(unaligned_references)]
/// Formats the substitutions of the primary_span
///
- /// The are a lot of conditions to this method, but in short:
+ /// There are a lot of conditions to this method, but in short:
///
/// * If the current `Diagnostic` has only one visible `CodeSuggestion`,
/// we format the `help` suggestion depending on the content of the
let line_offset = buffer.num_lines();
- let left = margin.left(source_string.len()); // Left trim
+ // Left trim
+ let left = margin.left(source_string.len());
+
// Account for unicode characters of width !=0 that were removed.
let left = source_string
.chars()
suggestions.iter().take(MAX_SUGGESTIONS)
{
notice_capitalization |= only_capitalization;
- // Only show underline if the suggestion spans a single line and doesn't cover the
- // entirety of the code output. If you have multiple replacements in the same line
- // of code, show the underline.
- let show_underline = !(parts.len() == 1 && parts[0].snippet.trim() == complete.trim())
- && complete.lines().count() == 1;
let has_deletion = parts.iter().any(|p| p.is_deletion());
let is_multiline = complete.lines().count() > 1;
- let show_diff = has_deletion && !is_multiline;
+ enum DisplaySuggestion {
+ Underline,
+ Diff,
+ None,
+ }
+
+ let show_code_change = if has_deletion && !is_multiline {
+ DisplaySuggestion::Diff
+ } else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim())
+ && !is_multiline
+ {
+ DisplaySuggestion::Underline
+ } else {
+ DisplaySuggestion::None
+ };
- if show_diff {
+ if let DisplaySuggestion::Diff = show_code_change {
row_num += 1;
}
&self.maybe_anonymized(line_start + line_pos),
Style::LineNumber,
);
- if show_diff {
+ if let DisplaySuggestion::Diff = show_code_change {
// Add the line number for both addition and removal to drive the point home.
//
// N - fn foo<A: T>(bar: A) {
let mut offsets: Vec<(usize, isize)> = Vec::new();
// Only show an underline in the suggestions if the suggestion is not the
// entirety of the code being shown and the displayed code is not multiline.
- if show_underline {
+ if let DisplaySuggestion::Diff | DisplaySuggestion::Underline = show_code_change {
draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
for part in parts {
let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
assert!(underline_start >= 0 && underline_end >= 0);
let padding: usize = max_line_num_len + 3;
for p in underline_start..underline_end {
- if !show_diff {
+ if let DisplaySuggestion::Underline = show_code_change {
// If this is a replacement, underline with `^`, if this is an addition
// underline with `+`.
buffer.putc(
);
}
}
- if show_diff {
+ if let DisplaySuggestion::Diff = show_code_change {
// Colorize removal with red in diff format.
buffer.set_style_range(
row_num - 2,
// if we elided some lines, add an ellipsis
if lines.next().is_some() {
buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber);
- } else if !show_underline {
+ } else if let DisplaySuggestion::None = show_code_change {
draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
row_num += 1;
}
('\t', " "), // We do our own tab replacement
('\u{200D}', ""), // Replace ZWJ with nothing for consistent terminal output of grapheme clusters.
('\u{202A}', ""), // The following unicode text flow control characters are inconsistently
- ('\u{202B}', ""), // supported accross CLIs and can cause confusion due to the bytes on disk
+ ('\u{202B}', ""), // supported across CLIs and can cause confusion due to the bytes on disk
('\u{202D}', ""), // not corresponding to the visible source code, so we replace them always.
('\u{202E}', ""),
('\u{2066}', ""),
self.tcx
}
- fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
+ fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> Result<ty::Binder<'tcx, T>, Self::Error>
where
T: TypeFoldable<'tcx>,
{
t
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(index, ..) => {
if index >= self.binder_index {
bug!("escaping late-bound region during canonicalization");
} else {
- r
+ Ok(r)
}
}
vid, r
);
let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
- self.canonicalize_region_mode.canonicalize_free_region(self, r)
+ Ok(self.canonicalize_region_mode.canonicalize_free_region(self, r))
}
ty::ReStatic
| ty::ReFree(_)
| ty::ReEmpty(_)
| ty::RePlaceholder(..)
- | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
+ | ty::ReErased => Ok(self.canonicalize_region_mode.canonicalize_free_region(self, r)),
}
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *t.kind() {
ty::Infer(ty::TyVar(vid)) => {
debug!("canonical: type var found with vid {:?}", vid);
Err(mut ui) => {
// FIXME: perf problem described in #55921.
ui = ty::UniverseIndex::ROOT;
- self.canonicalize_ty_var(
+ Ok(self.canonicalize_ty_var(
CanonicalVarInfo {
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
},
t,
- )
+ ))
}
}
}
- ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(
+ ty::Infer(ty::IntVar(_)) => Ok(self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
t,
- ),
+ )),
- ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(
+ ty::Infer(ty::FloatVar(_)) => Ok(self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
t,
- ),
+ )),
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("encountered a fresh type during canonicalization")
}
- ty::Placeholder(placeholder) => self.canonicalize_ty_var(
+ ty::Placeholder(placeholder) => Ok(self.canonicalize_ty_var(
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) },
t,
- ),
+ )),
ty::Bound(debruijn, _) => {
if debruijn >= self.binder_index {
bug!("escaping bound type during canonicalization")
} else {
- t
+ Ok(t)
}
}
if t.flags().intersects(self.needs_canonical_flags) {
t.super_fold_with(self)
} else {
- t
+ Ok(t)
}
}
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
match ct.val {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
debug!("canonical: const var found with vid {:?}", vid);
Err(mut ui) => {
// FIXME: perf problem described in #55921.
ui = ty::UniverseIndex::ROOT;
- return self.canonicalize_const_var(
+ return Ok(self.canonicalize_const_var(
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
ct,
- );
+ ));
}
}
}
if debruijn >= self.binder_index {
bug!("escaping bound type during canonicalization")
} else {
- return ct;
+ return Ok(ct);
}
}
ty::ConstKind::Placeholder(placeholder) => {
- return self.canonicalize_const_var(
+ return Ok(self.canonicalize_const_var(
CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) },
ct,
- );
+ ));
}
_ => {}
}
let flags = FlagComputation::for_const(ct);
- if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { ct }
+ if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { Ok(ct) }
}
}
indices: FxHashMap::default(),
binder_index: ty::INNERMOST,
};
- let out_value = value.fold_with(&mut canonicalizer);
+ let out_value = value.fold_with(&mut canonicalizer).into_ok();
// Once we have canonicalized `out_value`, it should not
// contain anything that ties it to this inference context
let infcx = self.infcx;
let bound_to = infcx.shallow_resolve(ty_var);
if bound_to != ty_var {
- self.fold_ty(bound_to)
+ self.fold_ty(bound_to).into_ok()
} else {
let var = self.canonical_var(info, ty_var.into());
self.tcx().mk_ty(ty::Bound(self.binder_index, var.into()))
let infcx = self.infcx;
let bound_to = infcx.shallow_resolve(const_var);
if bound_to != const_var {
- self.fold_const(bound_to)
+ self.fold_const(bound_to).into_ok()
} else {
let var = self.canonical_var(info, const_var.into());
self.tcx().mk_const(ty::Const {
val: ty::ConstKind::Bound(self.binder_index, var),
- ty: self.fold_ty(const_var.ty),
+ ty: self.fold_ty(const_var.ty).into_ok(),
})
}
}
F: FnOnce(u32) -> ty::InferTy,
{
if let Some(ty) = opt_ty {
- return ty.fold_with(self);
+ return ty.fold_with(self).into_ok();
}
match self.ty_freshen_map.entry(key) {
F: FnOnce(u32) -> ty::InferConst<'tcx>,
{
if let Some(ct) = opt_ct {
- return ct.fold_with(self);
+ return ct.fold_with(self).into_ok();
}
match self.const_freshen_map.entry(key) {
self.infcx.tcx
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(..) => {
// leave bound regions alone
- r
+ Ok(r)
}
ty::ReEarlyBound(..)
| ty::ReEmpty(_)
| ty::ReErased => {
// replace all free regions with 'erased
- self.tcx().lifetimes.re_erased
+ Ok(self.tcx().lifetimes.re_erased)
}
ty::ReStatic => {
if self.keep_static {
- r
+ Ok(r)
} else {
- self.tcx().lifetimes.re_erased
+ Ok(self.tcx().lifetimes.re_erased)
}
}
}
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.needs_infer() && !t.has_erasable_regions(self.tcx()) {
- return t;
+ return Ok(t);
}
let tcx = self.infcx.tcx;
match *t.kind() {
ty::Infer(ty::TyVar(v)) => {
let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
- self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy)
+ Ok(self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy))
}
- ty::Infer(ty::IntVar(v)) => self.freshen_ty(
+ ty::Infer(ty::IntVar(v)) => Ok(self.freshen_ty(
self.infcx
.inner
.borrow_mut()
.map(|v| v.to_type(tcx)),
ty::IntVar(v),
ty::FreshIntTy,
- ),
+ )),
- ty::Infer(ty::FloatVar(v)) => self.freshen_ty(
+ ty::Infer(ty::FloatVar(v)) => Ok(self.freshen_ty(
self.infcx
.inner
.borrow_mut()
.map(|v| v.to_type(tcx)),
ty::FloatVar(v),
ty::FreshFloatTy,
- ),
+ )),
ty::Infer(ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct)) => {
if ct >= self.ty_freshen_count {
self.ty_freshen_count
);
}
- t
+ Ok(t)
}
ty::Generator(..)
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
match ct.val {
ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
let opt_ct = self
.probe_value(v)
.val
.known();
- return self.freshen_const(
+ return Ok(self.freshen_const(
opt_ct,
ty::InferConst::Var(v),
ty::InferConst::Fresh,
ct.ty,
- );
+ ));
}
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
if i >= self.const_freshen_count {
self.const_freshen_count,
);
}
- return ct;
+ return Ok(ct);
}
ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
{
Ok(value)
} else {
- Ok(value.fold_with(&mut fudger))
+ Ok(value.fold_with(&mut fudger).into_ok())
}
}
}
self.infcx.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *ty.kind() {
ty::Infer(ty::InferTy::TyVar(vid)) => {
if self.type_vars.0.contains(&vid) {
// Recreate it with a fresh variable here.
let idx = (vid.as_usize() - self.type_vars.0.start.as_usize()) as usize;
let origin = self.type_vars.1[idx];
- self.infcx.next_ty_var(origin)
+ Ok(self.infcx.next_ty_var(origin))
} else {
// This variable was created before the
// "fudging". Since we refresh all type
debug_assert!(
self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown()
);
- ty
+ Ok(ty)
}
}
ty::Infer(ty::InferTy::IntVar(vid)) => {
- if self.int_vars.contains(&vid) {
- self.infcx.next_int_var()
- } else {
- ty
- }
+ Ok(if self.int_vars.contains(&vid) { self.infcx.next_int_var() } else { ty })
}
ty::Infer(ty::InferTy::FloatVar(vid)) => {
- if self.float_vars.contains(&vid) {
- self.infcx.next_float_var()
- } else {
- ty
- }
+ Ok(if self.float_vars.contains(&vid) { self.infcx.next_float_var() } else { ty })
}
_ => ty.super_fold_with(self),
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
if let ty::ReVar(vid) = *r {
if self.region_vars.0.contains(&vid) {
let idx = vid.index() - self.region_vars.0.start.index();
let origin = self.region_vars.1[idx];
- return self.infcx.next_region_var(origin);
+ return Ok(self.infcx.next_region_var(origin));
}
}
- r
+ Ok(r)
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if let ty::Const { val: ty::ConstKind::Infer(ty::InferConst::Var(vid)), ty } = ct {
if self.const_vars.0.contains(&vid) {
// This variable was created during the fudging.
// Recreate it with a fresh variable here.
let idx = (vid.index - self.const_vars.0.start.index) as usize;
let origin = self.const_vars.1[idx];
- self.infcx.next_const_var(ty, origin)
+ Ok(self.infcx.next_const_var(ty, origin))
} else {
- ct
+ Ok(ct)
}
} else {
ct.super_fold_with(self)
}
pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T {
- t.fold_with(&mut self.freshener())
+ t.fold_with(&mut self.freshener()).into_ok()
}
/// Returns the origin of the type variable identified by `vid`, or `None`
where
T: TypeFoldable<'tcx>,
{
- value.fold_with(&mut ShallowResolver { infcx: self })
+ value.fold_with(&mut ShallowResolver { infcx: self }).into_ok()
}
pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
return value; // Avoid duplicated subst-folding.
}
let mut r = resolve::OpportunisticVarResolver::new(self);
- value.fold_with(&mut r)
+ value.fold_with(&mut r).into_ok()
}
/// Returns the first unresolved variable contained in `T`. In the
self.infcx.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- self.infcx.shallow_resolve_ty(ty)
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ Ok(self.infcx.shallow_resolve_ty(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 {
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ Ok(if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct {
self.infcx
.inner
.borrow_mut()
.unwrap_or(ct)
} else {
ct
- }
+ })
}
}
impl<'a, 'tcx> Instantiator<'a, 'tcx> {
fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
let tcx = self.infcx.tcx;
- value.fold_with(&mut BottomUpFolder {
- tcx,
- ty_op: |ty| {
- if ty.references_error() {
- return tcx.ty_error();
- } else if let ty::Opaque(def_id, substs) = ty.kind() {
- // Check that this is `impl Trait` type is
- // declared by `parent_def_id` -- i.e., one whose
- // value we are inferring. At present, this is
- // always true during the first phase of
- // type-check, but not always true later on during
- // NLL. Once we support named opaque types more fully,
- // this same scenario will be able to arise during all phases.
- //
- // Here is an example using type alias `impl Trait`
- // that indicates the distinction we are checking for:
- //
- // ```rust
- // mod a {
- // pub type Foo = impl Iterator;
- // pub fn make_foo() -> Foo { .. }
- // }
- //
- // mod b {
- // fn foo() -> a::Foo { a::make_foo() }
- // }
- // ```
- //
- // Here, the return type of `foo` references an
- // `Opaque` indeed, but not one whose value is
- // presently being inferred. You can get into a
- // similar situation with closure return types
- // today:
- //
- // ```rust
- // fn foo() -> impl Iterator { .. }
- // fn bar() {
- // let x = || foo(); // returns the Opaque assoc with `foo`
- // }
- // ```
- if let Some(def_id) = def_id.as_local() {
- let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let parent_def_id = self.infcx.defining_use_anchor;
- let def_scope_default = || {
- let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
- parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
- };
- let (in_definition_scope, origin) =
- match tcx.hir().expect_item(opaque_hir_id).kind {
- // Anonymous `impl Trait`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: Some(parent),
- origin,
- ..
- }) => (parent == parent_def_id.to_def_id(), origin),
- // Named `type Foo = impl Bar;`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: None,
- origin,
- ..
- }) => (
- may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
- origin,
- ),
- _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
+ value
+ .fold_with(&mut BottomUpFolder {
+ tcx,
+ ty_op: |ty| {
+ if ty.references_error() {
+ return tcx.ty_error();
+ } else if let ty::Opaque(def_id, substs) = ty.kind() {
+ // Check that this is `impl Trait` type is
+ // declared by `parent_def_id` -- i.e., one whose
+ // value we are inferring. At present, this is
+ // always true during the first phase of
+ // type-check, but not always true later on during
+ // NLL. Once we support named opaque types more fully,
+ // this same scenario will be able to arise during all phases.
+ //
+ // Here is an example using type alias `impl Trait`
+ // that indicates the distinction we are checking for:
+ //
+ // ```rust
+ // mod a {
+ // pub type Foo = impl Iterator;
+ // pub fn make_foo() -> Foo { .. }
+ // }
+ //
+ // mod b {
+ // fn foo() -> a::Foo { a::make_foo() }
+ // }
+ // ```
+ //
+ // Here, the return type of `foo` references an
+ // `Opaque` indeed, but not one whose value is
+ // presently being inferred. You can get into a
+ // similar situation with closure return types
+ // today:
+ //
+ // ```rust
+ // fn foo() -> impl Iterator { .. }
+ // fn bar() {
+ // let x = || foo(); // returns the Opaque assoc with `foo`
+ // }
+ // ```
+ if let Some(def_id) = def_id.as_local() {
+ let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let parent_def_id = self.infcx.defining_use_anchor;
+ let def_scope_default = || {
+ let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
+ parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
};
- if in_definition_scope {
- let opaque_type_key =
- OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
- return self.fold_opaque_ty(ty, opaque_type_key, origin);
- }
-
- debug!(
- "instantiate_opaque_types_in_map: \
+ let (in_definition_scope, origin) =
+ match tcx.hir().expect_item(def_id).kind {
+ // Anonymous `impl Trait`
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ impl_trait_fn: Some(parent),
+ origin,
+ ..
+ }) => (parent == parent_def_id.to_def_id(), origin),
+ // Named `type Foo = impl Bar;`
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ impl_trait_fn: None,
+ origin,
+ ..
+ }) => (
+ may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
+ origin,
+ ),
+ _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
+ };
+ if in_definition_scope {
+ let opaque_type_key =
+ OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
+ return self.fold_opaque_ty(ty, opaque_type_key, origin);
+ }
+
+ debug!(
+ "instantiate_opaque_types_in_map: \
encountered opaque outside its definition scope \
def_id={:?}",
- def_id,
- );
+ def_id,
+ );
+ }
}
- }
- ty
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- })
+ ty
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ })
+ .into_ok()
}
#[instrument(skip(self), level = "debug")]
debug!(?predicate);
// We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
- let predicate = predicate.fold_with(&mut BottomUpFolder {
- tcx,
- ty_op: |ty| match ty.kind() {
- ty::Projection(projection_ty) => infcx.infer_projection(
- self.param_env,
- *projection_ty,
- traits::ObligationCause::misc(self.value_span, self.body_id),
- 0,
- &mut self.obligations,
- ),
- _ => ty,
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- });
+ let predicate = predicate
+ .fold_with(&mut BottomUpFolder {
+ tcx,
+ ty_op: |ty| match ty.kind() {
+ ty::Projection(projection_ty) => infcx.infer_projection(
+ self.param_env,
+ *projection_ty,
+ traits::ObligationCause::misc(self.value_span, self.body_id),
+ 0,
+ &mut self.obligations,
+ ),
+ _ => ty,
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ })
+ .into_ok();
debug!(?predicate);
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
self.infcx.tcx
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.has_infer_types_or_consts() {
- t // micro-optimize -- if there is nothing in this type that this fold affects...
+ Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.infcx.shallow_resolve(t);
t.super_fold_with(self)
}
}
- fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> {
+ fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> Result<&'tcx Const<'tcx>, Self::Error> {
if !ct.has_infer_types_or_consts() {
- ct // micro-optimize -- if there is nothing in this const that this fold affects...
+ Ok(ct) // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let ct = self.infcx.shallow_resolve(ct);
ct.super_fold_with(self)
}
}
- fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ fn fold_mir_const(
+ &mut self,
+ constant: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
constant.super_fold_with(self)
}
}
self.infcx.tcx
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.has_infer_regions() {
- t // micro-optimize -- if there is nothing in this type that this fold affects...
+ Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
t.super_fold_with(self)
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- match *r {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ Ok(match *r {
ty::ReVar(rid) => {
let resolved = self
.infcx
self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved))
}
_ => r,
- }
+ })
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if !ct.has_infer_regions() {
- ct // micro-optimize -- if there is nothing in this const that this fold affects...
+ Ok(ct) // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
ct.super_fold_with(self)
}
where
T: TypeFoldable<'tcx>,
{
- let mut full_resolver = FullTypeResolver { infcx, err: None };
- let result = value.fold_with(&mut full_resolver);
- match full_resolver.err {
- None => Ok(result),
- Some(e) => Err(e),
- }
+ value.fold_with(&mut FullTypeResolver { infcx })
}
// N.B. This type is not public because the protocol around checking the
// `err` field is not enforceable otherwise.
struct FullTypeResolver<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
- err: Option<FixupError<'tcx>>,
}
impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
+ type Error = FixupError<'tcx>;
+
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.needs_infer() {
- t // micro-optimize -- if there is nothing in this type that this fold affects...
+ Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.infcx.shallow_resolve(t);
match *t.kind() {
- ty::Infer(ty::TyVar(vid)) => {
- self.err = Some(FixupError::UnresolvedTy(vid));
- self.tcx().ty_error()
- }
- ty::Infer(ty::IntVar(vid)) => {
- self.err = Some(FixupError::UnresolvedIntTy(vid));
- self.tcx().ty_error()
- }
- ty::Infer(ty::FloatVar(vid)) => {
- self.err = Some(FixupError::UnresolvedFloatTy(vid));
- self.tcx().ty_error()
- }
+ ty::Infer(ty::TyVar(vid)) => Err(FixupError::UnresolvedTy(vid)),
+ ty::Infer(ty::IntVar(vid)) => Err(FixupError::UnresolvedIntTy(vid)),
+ ty::Infer(ty::FloatVar(vid)) => Err(FixupError::UnresolvedFloatTy(vid)),
ty::Infer(_) => {
bug!("Unexpected type in full type resolver: {:?}", t);
}
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
- ty::ReVar(rid) => self
+ ty::ReVar(rid) => Ok(self
.infcx
.lexical_region_resolutions
.borrow()
.as_ref()
.expect("region resolution not performed")
- .resolve_var(rid),
- _ => r,
+ .resolve_var(rid)),
+ _ => Ok(r),
}
}
- fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if !c.needs_infer() {
- c // micro-optimize -- if there is nothing in this const that this fold affects...
+ Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let c = self.infcx.shallow_resolve(c);
match c.val {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
- self.err = Some(FixupError::UnresolvedConst(vid));
- return self.tcx().const_error(c.ty);
+ return Err(FixupError::UnresolvedConst(vid));
}
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
bug!("Unexpected const in full const resolver: {:?}", c);
#![feature(control_flow_enum)]
#![feature(min_specialization)]
#![feature(label_break_value)]
+#![feature(unwrap_infallible)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]
// TypeFoldable implementations.
impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- traits::Obligation {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(traits::Obligation {
cause: self.cause,
recursion_depth: self.recursion_depth,
- predicate: self.predicate.fold_with(folder),
- param_env: self.param_env.fold_with(folder),
- }
+ predicate: self.predicate.fold_with(folder)?,
+ param_env: self.param_env.fold_with(folder)?,
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
warn_if_doc(cx, expr.span, "expressions", &expr.attrs);
}
+
+ fn check_generic_param(&mut self, cx: &EarlyContext<'_>, param: &ast::GenericParam) {
+ warn_if_doc(cx, param.ident.span, "generic parameters", ¶m.attrs);
+ }
}
declare_lint! {
this_decl_ty,
CItemKind::Declaration,
) {
- let orig_fi = tcx.hir().expect_foreign_item(existing_hid);
+ let orig_fi = tcx.hir().expect_foreign_item(existing_hid.expect_owner());
let orig = Self::name_of_extern_decl(tcx, orig_fi);
// We want to ensure that we use spans for both decls that include where the
impl<'tcx> LateLintPass<'tcx> for EnumIntrinsicsNonEnums {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
- if let hir::ExprKind::Call(ref func, ref args) = expr.kind {
- if let hir::ExprKind::Path(ref qpath) = func.kind {
- if let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() {
- if cx.tcx.is_diagnostic_item(sym::mem_discriminant, def_id) {
- enforce_mem_discriminant(cx, func, expr.span, args[0].span);
- } else if cx.tcx.is_diagnostic_item(sym::mem_variant_count, def_id) {
- enforce_mem_variant_count(cx, func, expr.span);
- }
- }
- }
+ let hir::ExprKind::Call(func, args) = &expr.kind else { return };
+ let hir::ExprKind::Path(qpath) = &func.kind else { return };
+ let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() else { return };
+ let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return };
+ match name {
+ sym::mem_discriminant => enforce_mem_discriminant(cx, func, expr.span, args[0].span),
+ sym::mem_variant_count => enforce_mem_variant_count(cx, func, expr.span),
+ _ => {}
}
}
}
#![cfg_attr(bootstrap, feature(format_args_capture))]
#![feature(iter_order_by)]
#![feature(iter_zip)]
+#![feature(let_else)]
#![feature(never_type)]
#![feature(nll)]
#![feature(control_flow_enum)]
// Unwrap more levels of macro expansion, as panic_2015!()
// was likely expanded from panic!() and possibly from
// [debug_]assert!().
- for &i in
- &[sym::std_panic_macro, sym::core_panic_macro, sym::assert_macro, sym::debug_assert_macro]
- {
+ loop {
let parent = expn.call_site.ctxt().outer_expn_data();
- if parent.macro_def_id.map_or(false, |id| cx.tcx.is_diagnostic_item(i, id)) {
- expn = parent;
- panic_macro = i;
+ let Some(id) = parent.macro_def_id else { break };
+ let Some(name) = cx.tcx.get_diagnostic_name(id) else { break };
+ if !matches!(
+ name,
+ sym::core_panic_macro
+ | sym::std_panic_macro
+ | sym::assert_macro
+ | sym::debug_assert_macro
+ ) {
+ break;
}
+ expn = parent;
+ panic_macro = name;
}
let macro_symbol =
_ => return,
};
// (Re)check that it implements the noop diagnostic.
- for s in [sym::noop_method_clone, sym::noop_method_deref, sym::noop_method_borrow].iter() {
- if cx.tcx.is_diagnostic_item(*s, i.def_id()) {
- let method = &call.ident.name;
- let receiver = &elements[0];
- let receiver_ty = cx.typeck_results().expr_ty(receiver);
- let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
- if receiver_ty != expr_ty {
- // This lint will only trigger if the receiver type and resulting expression \
- // type are the same, implying that the method call is unnecessary.
- return;
- }
- let expr_span = expr.span;
- let note = format!(
- "the type `{:?}` which `{}` is being called on is the same as \
- the type returned from `{}`, so the method call does not do \
- anything and can be removed",
- receiver_ty, method, method,
- );
-
- let span = expr_span.with_lo(receiver.span.hi());
- cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
- let method = &call.ident.name;
- let message = format!(
- "call to `.{}()` on a reference in this situation does nothing",
- &method,
- );
- lint.build(&message)
- .span_label(span, "unnecessary method call")
- .note(¬e)
- .emit()
- });
- }
+ let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
+ if !matches!(
+ name,
+ sym::noop_method_borrow | sym::noop_method_clone | sym::noop_method_deref
+ ) {
+ return;
}
+ let method = &call.ident.name;
+ let receiver = &elements[0];
+ let receiver_ty = cx.typeck_results().expr_ty(receiver);
+ let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
+ if receiver_ty != expr_ty {
+ // This lint will only trigger if the receiver type and resulting expression \
+ // type are the same, implying that the method call is unnecessary.
+ return;
+ }
+ let expr_span = expr.span;
+ let note = format!(
+ "the type `{:?}` which `{}` is being called on is the same as \
+ the type returned from `{}`, so the method call does not do \
+ anything and can be removed",
+ receiver_ty, method, method,
+ );
+
+ let span = expr_span.with_lo(receiver.span.hi());
+ cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
+ let method = &call.ident.name;
+ let message =
+ format!("call to `.{}()` on a reference in this situation does nothing", &method,);
+ lint.build(&message).span_label(span, "unnecessary method call").note(¬e).emit()
+ });
}
}
let layout = match cx.layout_of(ty) {
Ok(layout) => layout,
Err(
- ty::layout::LayoutError::Unknown(_) | ty::layout::LayoutError::SizeOverflow(_),
+ ty::layout::LayoutError::Unknown(_)
+ | ty::layout::LayoutError::SizeOverflow(_)
+ | ty::layout::LayoutError::NormalizationFailure(_, _),
) => return,
};
let (variants, tag) = match layout.variants {
struct LLVMRustCounterMappingRegion {
coverage::Counter Count;
+ coverage::Counter FalseCount;
uint32_t FileID;
uint32_t ExpandedFileID;
uint32_t LineStart;
MappingRegions.reserve(NumMappingRegions);
for (const auto &Region : makeArrayRef(RustMappingRegions, NumMappingRegions)) {
MappingRegions.emplace_back(
- Region.Count, Region.FileID, Region.ExpandedFileID,
+ Region.Count, Region.FalseCount, Region.FileID, Region.ExpandedFileID,
Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,
Region.Kind);
}
}
extern "C" uint32_t LLVMRustCoverageMappingVersion() {
- return coverage::CovMapVersion::Version4;
+#if LLVM_VERSION_GE(13, 0)
+ return coverage::CovMapVersion::Version6;
+#else
+ return coverage::CovMapVersion::Version5;
+#endif
}
#include "LLVMWrapper.h"
#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/DiagnosticHandler.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/GlobalVariable.h"
case DK_SampleProfile:
return LLVMRustDiagnosticKind::SampleProfile;
case DK_OptimizationRemark:
+ case DK_MachineOptimizationRemark:
return LLVMRustDiagnosticKind::OptimizationRemark;
case DK_OptimizationRemarkMissed:
+ case DK_MachineOptimizationRemarkMissed:
return LLVMRustDiagnosticKind::OptimizationRemarkMissed;
case DK_OptimizationRemarkAnalysis:
+ case DK_MachineOptimizationRemarkAnalysis:
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysis;
case DK_OptimizationRemarkAnalysisFPCommute:
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisFPCommute;
return LLVMRustResult::Success;
}
}
+
+// Transfers ownership of DiagnosticHandler unique_ptr to the caller.
+extern "C" DiagnosticHandler *
+LLVMRustContextGetDiagnosticHandler(LLVMContextRef C) {
+ std::unique_ptr<DiagnosticHandler> DH = unwrap(C)->getDiagnosticHandler();
+ return DH.release();
+}
+
+// Sets unique_ptr to object of DiagnosticHandler to provide custom diagnostic
+// handling. Ownership of the handler is moved to the LLVMContext.
+extern "C" void LLVMRustContextSetDiagnosticHandler(LLVMContextRef C,
+ DiagnosticHandler *DH) {
+ unwrap(C)->setDiagnosticHandler(std::unique_ptr<DiagnosticHandler>(DH));
+}
+
+using LLVMDiagnosticHandlerTy = DiagnosticHandler::DiagnosticHandlerTy;
+
+// Configures a diagnostic handler that invokes provided callback when a
+// backend needs to emit a diagnostic.
+//
+// When RemarkAllPasses is true, remarks are enabled for all passes. Otherwise
+// the RemarkPasses array specifies individual passes for which remarks will be
+// enabled.
+extern "C" void LLVMRustContextConfigureDiagnosticHandler(
+ LLVMContextRef C, LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
+ void *DiagnosticHandlerContext, bool RemarkAllPasses,
+ const char * const * RemarkPasses, size_t RemarkPassesLen) {
+
+ class RustDiagnosticHandler final : public DiagnosticHandler {
+ public:
+ RustDiagnosticHandler(LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
+ void *DiagnosticHandlerContext,
+ bool RemarkAllPasses,
+ std::vector<std::string> RemarkPasses)
+ : DiagnosticHandlerCallback(DiagnosticHandlerCallback),
+ DiagnosticHandlerContext(DiagnosticHandlerContext),
+ RemarkAllPasses(RemarkAllPasses),
+ RemarkPasses(RemarkPasses) {}
+
+ virtual bool handleDiagnostics(const DiagnosticInfo &DI) override {
+ if (DiagnosticHandlerCallback) {
+ DiagnosticHandlerCallback(DI, DiagnosticHandlerContext);
+ return true;
+ }
+ return false;
+ }
+
+ bool isAnalysisRemarkEnabled(StringRef PassName) const override {
+ return isRemarkEnabled(PassName);
+ }
+
+ bool isMissedOptRemarkEnabled(StringRef PassName) const override {
+ return isRemarkEnabled(PassName);
+ }
+
+ bool isPassedOptRemarkEnabled(StringRef PassName) const override {
+ return isRemarkEnabled(PassName);
+ }
+
+ bool isAnyRemarkEnabled() const override {
+ return RemarkAllPasses || !RemarkPasses.empty();
+ }
+
+ private:
+ bool isRemarkEnabled(StringRef PassName) const {
+ if (RemarkAllPasses)
+ return true;
+
+ for (auto &Pass : RemarkPasses)
+ if (Pass == PassName)
+ return true;
+
+ return false;
+ }
+
+ LLVMDiagnosticHandlerTy DiagnosticHandlerCallback = nullptr;
+ void *DiagnosticHandlerContext = nullptr;
+
+ bool RemarkAllPasses = false;
+ std::vector<std::string> RemarkPasses;
+ };
+
+ std::vector<std::string> Passes;
+ for (size_t I = 0; I != RemarkPassesLen; ++I)
+ Passes.push_back(RemarkPasses[I]);
+
+ unwrap(C)->setDiagnosticHandler(std::make_unique<RustDiagnosticHandler>(
+ DiagnosticHandlerCallback, DiagnosticHandlerContext, RemarkAllPasses, Passes));
+}
vi.construct(|_, index| {
let bind = &bindings[index];
quote! {
- ::rustc_middle::ty::fold::TypeFoldable::fold_with(#bind, __folder)
+ ::rustc_middle::ty::fold::TypeFoldable::fold_with(#bind, __folder)?
}
})
});
fn super_fold_with<__F: ::rustc_middle::ty::fold::TypeFolder<'tcx>>(
self,
__folder: &mut __F
- ) -> Self {
- match self { #body_fold }
+ ) -> Result<Self, __F::Error> {
+ Ok(match self { #body_fold })
}
fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>(
debug!("EncodeContext::encode_info_for_trait_item({:?})", def_id);
let tcx = self.tcx;
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let ast_item = tcx.hir().expect_trait_item(hir_id);
+ let ast_item = tcx.hir().expect_trait_item(def_id.expect_local());
let trait_item = tcx.associated_item(def_id);
let container = match trait_item.defaultness {
debug!("EncodeContext::encode_info_for_impl_item({:?})", def_id);
let tcx = self.tcx;
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let ast_item = self.tcx.hir().expect_impl_item(hir_id);
+ let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
let impl_item = self.tcx.associated_item(def_id);
let container = match impl_item.defaultness {
fn encode_lib_features(&mut self) -> Lazy<[(Symbol, Option<Symbol>)]> {
empty_proc_macro!(self);
let tcx = self.tcx;
- let lib_features = tcx.lib_features();
+ let lib_features = tcx.lib_features(());
self.lazy(lib_features.to_vec())
}
bug!("expected foreign mod or inlined parent, found {}", self.node_to_string(parent))
}
- pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_item(&self, id: LocalDefId) -> &'hir Item<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::Item(item), .. }) => item,
- _ => bug!("expected item, found {}", self.node_to_string(id)),
+ _ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
- pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_impl_item(&self, id: LocalDefId) -> &'hir ImplItem<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
- _ => bug!("expected impl item, found {}", self.node_to_string(id)),
+ _ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
- pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_trait_item(&self, id: LocalDefId) -> &'hir TraitItem<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
- _ => bug!("expected trait item, found {}", self.node_to_string(id)),
+ _ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))),
}
}
}
}
- pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> {
- match self.tcx.hir_owner(id.expect_owner()) {
+ pub fn expect_foreign_item(&self, id: LocalDefId) -> &'hir ForeignItem<'hir> {
+ match self.tcx.hir_owner(id) {
Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
- _ => bug!("expected foreign item, found {}", self.node_to_string(id)),
+ _ => {
+ bug!("expected foreign item, found {}", self.node_to_string(HirId::make_owner(id)))
+ }
}
}
#![feature(try_blocks)]
#![feature(try_reserve_kind)]
#![feature(nonzero_ops)]
+#![feature(unwrap_infallible)]
#![recursion_limit = "512"]
#[macro_use]
fn super_fold_with<F: $crate::ty::fold::TypeFolder<$tcx>>(
self,
_: &mut F
- ) -> $ty {
- self
+ ) -> ::std::result::Result<$ty, F::Error> {
+ Ok(self)
}
fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
fn super_fold_with<V: $crate::ty::fold::TypeFolder<$tcx>>(
self,
folder: &mut V,
- ) -> Self {
+ ) -> ::std::result::Result<Self, V::Error> {
EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output())
}
};
(@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
- match $this {
+ Ok(match $this {
$($output)*
- }
+ })
};
(@FoldVariants($this:expr, $folder:expr)
output(
$variant ( $($variant_arg),* ) => {
$variant (
- $($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)),*
+ $($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)?),*
)
}
$($output)*
$variant {
$($variant_arg: $crate::ty::fold::TypeFoldable::fold_with(
$variant_arg, $folder
- )),* }
+ )?),* }
}
$($output)*
)
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html
use crate::ty::TyCtxt;
-use rustc_hir as hir;
-use rustc_hir::Node;
-use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
-
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir as hir;
+use rustc_hir::Node;
use rustc_macros::HashStable;
+use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
use rustc_span::{Span, DUMMY_SP};
use std::fmt;
/// If not empty, this body is the root of this region hierarchy.
pub root_body: Option<hir::HirId>,
- /// The parent of the root body owner, if the latter is an
- /// an associated const or method, as impls/traits can also
- /// have lifetime parameters free in this body.
- pub root_parent: Option<hir::HirId>,
-
/// Maps from a scope ID to the enclosing scope id;
/// this is usually corresponding to the lexical nesting, though
/// in the case of closures the parent scope is the innermost
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let ScopeTree {
root_body,
- root_parent,
ref body_expr_count,
ref parent_map,
ref var_map,
} = *self;
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
- root_body.hash_stable(hcx, hasher);
- root_parent.hash_stable(hcx, hasher);
+ root_body.hash_stable(hcx, hasher)
});
body_expr_count.hash_stable(hcx, hasher);
impl ExpressionOperandId {
/// An expression operand for a "zero counter", as described in the following references:
///
- /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter>
- /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#tag>
- /// * <https://github.com/rust-lang/llvm-project/blob/rustc/11.0-2020-10-12/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#tag>
+ /// * <https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
///
/// This operand can be used to count two or more separate code regions with a single counter,
/// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
}
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(InterpError<'_>, 64);
-
pub enum InterpError<'tcx> {
/// The program caused undefined behavior.
UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
TrivialTypeFoldableAndLiftImpls! { ProjectionKind, }
impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- UserTypeProjection {
- base: self.base.fold_with(folder),
- projs: self.projs.fold_with(folder),
- }
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(UserTypeProjection {
+ base: self.base.fold_with(folder)?,
+ projs: self.projs.fold_with(folder)?,
+ })
}
fn super_visit_with<Vs: TypeVisitor<'tcx>>(
}
impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
use crate::mir::TerminatorKind::*;
let kind = match self.kind {
Goto { target } => Goto { target },
SwitchInt { discr, switch_ty, targets } => SwitchInt {
- discr: discr.fold_with(folder),
- switch_ty: switch_ty.fold_with(folder),
+ discr: discr.fold_with(folder)?,
+ switch_ty: switch_ty.fold_with(folder)?,
targets,
},
Drop { place, target, unwind } => {
- Drop { place: place.fold_with(folder), target, unwind }
+ Drop { place: place.fold_with(folder)?, target, unwind }
}
DropAndReplace { place, value, target, unwind } => DropAndReplace {
- place: place.fold_with(folder),
- value: value.fold_with(folder),
+ place: place.fold_with(folder)?,
+ value: value.fold_with(folder)?,
target,
unwind,
},
Yield { value, resume, resume_arg, drop } => Yield {
- value: value.fold_with(folder),
+ value: value.fold_with(folder)?,
resume,
- resume_arg: resume_arg.fold_with(folder),
+ resume_arg: resume_arg.fold_with(folder)?,
drop,
},
Call { func, args, destination, cleanup, from_hir_call, fn_span } => {
- let dest = destination.map(|(loc, dest)| (loc.fold_with(folder), dest));
+ let dest = destination
+ .map(|(loc, dest)| (loc.fold_with(folder).map(|loc| (loc, dest))))
+ .transpose()?;
Call {
- func: func.fold_with(folder),
- args: args.fold_with(folder),
+ func: func.fold_with(folder)?,
+ args: args.fold_with(folder)?,
destination: dest,
cleanup,
from_hir_call,
use AssertKind::*;
let msg = match msg {
BoundsCheck { len, index } => {
- BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
+ BoundsCheck { len: len.fold_with(folder)?, index: index.fold_with(folder)? }
}
- Overflow(op, l, r) => Overflow(op, l.fold_with(folder), r.fold_with(folder)),
- OverflowNeg(op) => OverflowNeg(op.fold_with(folder)),
- DivisionByZero(op) => DivisionByZero(op.fold_with(folder)),
- RemainderByZero(op) => RemainderByZero(op.fold_with(folder)),
+ Overflow(op, l, r) => Overflow(op, l.fold_with(folder)?, r.fold_with(folder)?),
+ OverflowNeg(op) => OverflowNeg(op.fold_with(folder)?),
+ DivisionByZero(op) => DivisionByZero(op.fold_with(folder)?),
+ RemainderByZero(op) => RemainderByZero(op.fold_with(folder)?),
ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg,
};
- Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
+ Assert { cond: cond.fold_with(folder)?, expected, msg, target, cleanup }
}
GeneratorDrop => GeneratorDrop,
Resume => Resume,
FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
InlineAsm { template, operands, options, line_spans, destination } => InlineAsm {
template,
- operands: operands.fold_with(folder),
+ operands: operands.fold_with(folder)?,
options,
line_spans,
destination,
},
};
- Terminator { source_info: self.source_info, kind }
+ Ok(Terminator { source_info: self.source_info, kind })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(Place {
+ local: self.local.fold_with(folder)?,
+ projection: self.projection.fold_with(folder)?,
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v))
}
}
impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
use crate::mir::Rvalue::*;
- match self {
- Use(op) => Use(op.fold_with(folder)),
- Repeat(op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)),
- ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)),
- Ref(region, bk, place) => Ref(region.fold_with(folder), bk, place.fold_with(folder)),
- AddressOf(mutability, place) => AddressOf(mutability, place.fold_with(folder)),
- Len(place) => Len(place.fold_with(folder)),
- Cast(kind, op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
+ Ok(match self {
+ Use(op) => Use(op.fold_with(folder)?),
+ Repeat(op, len) => Repeat(op.fold_with(folder)?, len.fold_with(folder)?),
+ ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)?),
+ Ref(region, bk, place) => Ref(region.fold_with(folder)?, bk, place.fold_with(folder)?),
+ AddressOf(mutability, place) => AddressOf(mutability, place.fold_with(folder)?),
+ Len(place) => Len(place.fold_with(folder)?),
+ Cast(kind, op, ty) => Cast(kind, op.fold_with(folder)?, ty.fold_with(folder)?),
BinaryOp(op, box (rhs, lhs)) => {
- BinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder))))
+ BinaryOp(op, Box::new((rhs.fold_with(folder)?, lhs.fold_with(folder)?)))
}
CheckedBinaryOp(op, box (rhs, lhs)) => {
- CheckedBinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder))))
+ CheckedBinaryOp(op, Box::new((rhs.fold_with(folder)?, lhs.fold_with(folder)?)))
}
- UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)),
- Discriminant(place) => Discriminant(place.fold_with(folder)),
- NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)),
+ UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)?),
+ Discriminant(place) => Discriminant(place.fold_with(folder)?),
+ NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)?),
Aggregate(kind, fields) => {
- let kind = kind.map_id(|kind| match kind {
- AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
- AggregateKind::Tuple => AggregateKind::Tuple,
- AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
- def,
- v,
- substs.fold_with(folder),
- user_ty.fold_with(folder),
- n,
- ),
- AggregateKind::Closure(id, substs) => {
- AggregateKind::Closure(id, substs.fold_with(folder))
- }
- AggregateKind::Generator(id, substs, movablity) => {
- AggregateKind::Generator(id, substs.fold_with(folder), movablity)
- }
- });
- Aggregate(kind, fields.fold_with(folder))
+ let kind = kind.try_map_id(|kind| {
+ Ok(match kind {
+ AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)?),
+ AggregateKind::Tuple => AggregateKind::Tuple,
+ AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
+ def,
+ v,
+ substs.fold_with(folder)?,
+ user_ty.fold_with(folder)?,
+ n,
+ ),
+ AggregateKind::Closure(id, substs) => {
+ AggregateKind::Closure(id, substs.fold_with(folder)?)
+ }
+ AggregateKind::Generator(id, substs, movablity) => {
+ AggregateKind::Generator(id, substs.fold_with(folder)?, movablity)
+ }
+ })
+ })?;
+ Aggregate(kind, fields.fold_with(folder)?)
}
- ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder), ty.fold_with(folder)),
- }
+ ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder)?, ty.fold_with(folder)?),
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- match self {
- Operand::Copy(place) => Operand::Copy(place.fold_with(folder)),
- Operand::Move(place) => Operand::Move(place.fold_with(folder)),
- Operand::Constant(c) => Operand::Constant(c.fold_with(folder)),
- }
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(match self {
+ Operand::Copy(place) => Operand::Copy(place.fold_with(folder)?),
+ Operand::Move(place) => Operand::Move(place.fold_with(folder)?),
+ Operand::Constant(c) => Operand::Constant(c.fold_with(folder)?),
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
use crate::mir::ProjectionElem::*;
- match self {
+ Ok(match self {
Deref => Deref,
- Field(f, ty) => Field(f, ty.fold_with(folder)),
- Index(v) => Index(v.fold_with(folder)),
+ Field(f, ty) => Field(f, ty.fold_with(folder)?),
+ Index(v) => Index(v.fold_with(folder)?),
Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
ConstantIndex { offset, min_length, from_end } => {
ConstantIndex { offset, min_length, from_end }
}
Subslice { from, to, from_end } => Subslice { from, to, from_end },
- }
+ })
}
fn super_visit_with<Vs: TypeVisitor<'tcx>>(
}
impl<'tcx> TypeFoldable<'tcx> for Field {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
}
impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
}
impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- Constant {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(Constant {
span: self.span,
- user_ty: self.user_ty.fold_with(folder),
- literal: self.literal.fold_with(folder),
- }
+ user_ty: self.user_ty.fold_with(folder)?,
+ literal: self.literal.fold_with(folder)?,
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.literal.visit_with(visitor)?;
impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
#[inline(always)]
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.fold_mir_const(self)
}
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
match self {
- ConstantKind::Ty(c) => ConstantKind::Ty(c.fold_with(folder)),
- ConstantKind::Val(v, t) => ConstantKind::Val(v, t.fold_with(folder)),
+ ConstantKind::Ty(c) => Ok(ConstantKind::Ty(c.fold_with(folder)?)),
+ ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.fold_with(folder)?)),
}
}
if new_local == local { None } else { Some(PlaceElem::Index(new_local)) }
}
+ PlaceElem::Field(field, ty) => {
+ let mut new_ty = ty;
+ self.visit_ty(&mut new_ty, TyContext::Location(location));
+ if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
+ }
PlaceElem::Deref
- | PlaceElem::Field(..)
| PlaceElem::ConstantIndex { .. }
| PlaceElem::Subslice { .. }
| PlaceElem::Downcast(..) => None,
desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
}
- query get_lib_features(_: ()) -> LibFeatures {
+ query lib_features(_: ()) -> LibFeatures {
storage(ArenaCacheSelector<'tcx>)
- eval_always
desc { "calculating the lib features map" }
}
query defined_lib_features(_: CrateNum)
desc { "normalizing `{:?}`", goal }
}
+ // FIXME: Implement `normalize_generic_arg_after_erasing_regions` and
+ // `normalize_mir_const_after_erasing_regions` in terms of
+ // `try_normalize_generic_arg_after_erasing_regions` and
+ // `try_normalize_mir_const_after_erasing_regions`, respectively.
+
/// Do not call this query directly: invoke `normalize_erasing_regions` instead.
query normalize_generic_arg_after_erasing_regions(
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
desc { "normalizing `{}`", goal.value }
}
+ /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
+ query try_normalize_generic_arg_after_erasing_regions(
+ goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
+ ) -> Result<GenericArg<'tcx>, NoSolution> {
+ desc { "normalizing `{}`", goal.value }
+ }
+
+ /// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
+ query try_normalize_mir_const_after_erasing_regions(
+ goal: ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
+ ) -> Result<mir::ConstantKind<'tcx>, NoSolution> {
+ desc { "normalizing `{}`", goal.value }
+ }
+
query implied_outlives_bounds(
goal: CanonicalTyGoal<'tcx>
) -> Result<
use crate::hir::place::Place as HirPlace;
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
-use crate::middle;
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetimeDefault};
use crate::middle::stability;
use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
self.sess.consider_optimizing(&cname, msg)
}
- pub fn lib_features(self) -> &'tcx middle::lib_features::LibFeatures {
- self.get_lib_features(())
- }
-
/// Obtain all lang items of this crate and all dependencies (recursively)
pub fn lang_items(self) -> &'tcx rustc_hir::lang_items::LanguageItems {
self.get_lang_items(())
fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
// N.B., use `super_fold_with` here. If we used `fold_with`, it
// could invoke the `erase_regions_ty` query recursively.
- ty.super_fold_with(&mut RegionEraserVisitor { tcx })
+ ty.super_fold_with(&mut RegionEraserVisitor { tcx }).into_ok()
}
impl<'tcx> TyCtxt<'tcx> {
return value;
}
debug!("erase_regions({:?})", value);
- let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
+ let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self }).into_ok();
debug!("erase_regions = {:?}", value1);
value1
}
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if ty.needs_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) }
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ if ty.needs_infer() { ty.super_fold_with(self) } else { Ok(self.tcx.erase_regions_ty(ty)) }
}
- fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
+ fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> Result<ty::Binder<'tcx, T>, Self::Error>
where
T: TypeFoldable<'tcx>,
{
u.super_fold_with(self)
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
// because late-bound regions affect subtyping, we can't
// erase the bound/free distinction, but we can replace
// all free regions with 'erased.
// away. In codegen, they will always be erased to 'erased
// whenever a substitution occurs.
match *r {
- ty::ReLateBound(..) => r,
- _ => self.tcx.lifetimes.re_erased,
+ ty::ReLateBound(..) => Ok(r),
+ _ => Ok(self.tcx.lifetimes.re_erased),
}
}
- fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ fn fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
c.super_fold_with(self)
}
}
if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
let opaque_local_def_id = def_id.as_local();
let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
- let hir = self.hir();
- let opaque_hir_id = hir.local_def_id_to_hir_id(opaque_local_def_id);
- match &hir.expect_item(opaque_hir_id).kind {
+ match &self.hir().expect_item(opaque_local_def_id).kind {
hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
_ => bug!("The HirId comes from a `ty::Opaque`"),
}
///
/// To implement this conveniently, use the derive macro located in `rustc_macros`.
pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self;
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error>;
+ fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.super_fold_with(folder)
}
}
impl TypeFoldable<'tcx> for hir::Constness {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Self {
- self
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
/// identity fold, it should invoke `foo.fold_with(self)` to fold each
/// sub-item.
pub trait TypeFolder<'tcx>: Sized {
+ type Error = !;
+
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
- fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
+ fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
where
T: TypeFoldable<'tcx>,
{
t.super_fold_with(self)
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
t.super_fold_with(self)
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
r.super_fold_with(self)
}
- fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
c.super_fold_with(self)
}
- fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+ fn fold_predicate(
+ &mut self,
+ p: ty::Predicate<'tcx>,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error> {
p.super_fold_with(self)
}
- fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ fn fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
bug!("most type folders should not be folding MIR datastructures: {:?}", c)
}
}
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- let t = ty.super_fold_with(self);
- (self.ty_op)(t)
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ let t = ty.super_fold_with(self)?;
+ Ok((self.ty_op)(t))
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- let r = r.super_fold_with(self);
- (self.lt_op)(r)
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ let r = r.super_fold_with(self)?;
+ Ok((self.lt_op)(r))
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- let ct = ct.super_fold_with(self);
- (self.ct_op)(ct)
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ let ct = ct.super_fold_with(self)?;
+ Ok((self.ct_op)(ct))
}
}
where
T: TypeFoldable<'tcx>,
{
- value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
+ value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)).into_ok()
}
/// Invoke `callback` on every region appearing free in `value`.
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> ty::Binder<'tcx, T> {
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
}
#[instrument(skip(self), level = "debug")]
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(debruijn, _) if debruijn < self.current_index => {
debug!(?self.current_index, "skipped bound region");
*self.skipped_regions = true;
- r
+ Ok(r)
}
_ => {
debug!(?self.current_index, "folding free region");
- (self.fold_region_fn)(r, self.current_index)
+ Ok((self.fold_region_fn)(r, self.current_index))
}
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> ty::Binder<'tcx, T> {
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *t.kind() {
ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
if let Some(fld_t) = self.fld_t.as_mut() {
let ty = fld_t(bound_ty);
- return ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32());
+ return Ok(ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32()));
}
}
_ if t.has_vars_bound_at_or_above(self.current_index) => {
}
_ => {}
}
- t
+ Ok(t)
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
if let Some(fld_r) = self.fld_r.as_mut() {
// debruijn index. Then we adjust it to the
// correct depth.
assert_eq!(debruijn1, ty::INNERMOST);
- self.tcx.mk_region(ty::ReLateBound(debruijn, br))
+ Ok(self.tcx.mk_region(ty::ReLateBound(debruijn, br)))
} else {
- region
+ Ok(region)
};
}
}
_ => {}
}
- r
+ Ok(r)
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
match *ct {
ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty }
if debruijn == self.current_index =>
{
if let Some(fld_c) = self.fld_c.as_mut() {
let ct = fld_c(bound_const, ty);
- return ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32());
+ return Ok(ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32()));
}
}
_ if ct.has_vars_bound_at_or_above(self.current_index) => {
}
_ => {}
}
- ct
+ Ok(ct)
}
}
value
} else {
let mut replacer = BoundVarReplacer::new(self, Some(&mut real_fld_r), None, None);
- value.fold_with(&mut replacer)
+ value.fold_with(&mut replacer).into_ok()
};
(value, region_map)
}
} else {
let mut replacer =
BoundVarReplacer::new(self, Some(&mut fld_r), Some(&mut fld_t), Some(&mut fld_c));
- value.fold_with(&mut replacer)
+ value.fold_with(&mut replacer).into_ok()
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> ty::Binder<'tcx, T> {
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(debruijn, br) => {
if self.amount == 0 || debruijn < self.current_index {
- r
+ Ok(r)
} else {
let debruijn = debruijn.shifted_in(self.amount);
let shifted = ty::ReLateBound(debruijn, br);
- self.tcx.mk_region(shifted)
+ Ok(self.tcx.mk_region(shifted))
}
}
- _ => r,
+ _ => Ok(r),
}
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *ty.kind() {
ty::Bound(debruijn, bound_ty) => {
if self.amount == 0 || debruijn < self.current_index {
- ty
+ Ok(ty)
} else {
let debruijn = debruijn.shifted_in(self.amount);
- self.tcx.mk_ty(ty::Bound(debruijn, bound_ty))
+ Ok(self.tcx.mk_ty(ty::Bound(debruijn, bound_ty)))
}
}
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty } = *ct {
if self.amount == 0 || debruijn < self.current_index {
- ct
+ Ok(ct)
} else {
let debruijn = debruijn.shifted_in(self.amount);
- self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty })
+ Ok(self
+ .tcx
+ .mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty }))
}
} else {
ct.super_fold_with(self)
{
debug!("shift_vars(value={:?}, amount={})", value, amount);
- value.fold_with(&mut Shifter::new(tcx, amount))
+ value.fold_with(&mut Shifter::new(tcx, amount)).into_ok()
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
///
/// FIXME(@lcnr): explain this function a bit more
pub fn expose_default_const_substs<T: TypeFoldable<'tcx>>(self, v: T) -> T {
- v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self })
+ v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self }).into_ok()
}
}
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if ty.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
ty.super_fold_with(self)
} else {
- ty
+ Ok(ty)
}
}
- fn fold_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+ fn fold_predicate(
+ &mut self,
+ pred: ty::Predicate<'tcx>,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error> {
if pred.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
pred.super_fold_with(self)
} else {
- pred
+ Ok(pred)
}
}
}
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
debug!("fold_ty: ty={:?}", ty);
match ty.kind {
ty::Closure(def_id, substs) => {
ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
substs,
);
- if substs == polymorphized_substs {
+ Ok(if substs == polymorphized_substs {
ty
} else {
self.tcx.mk_closure(def_id, polymorphized_substs)
- }
+ })
}
ty::Generator(def_id, substs, movability) => {
let polymorphized_substs = polymorphize(
ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
substs,
);
- if substs == polymorphized_substs {
+ Ok(if substs == polymorphized_substs {
ty
} else {
self.tcx.mk_generator(def_id, polymorphized_substs, movability)
- }
+ })
}
_ => ty.super_fold_with(self),
}
// ..and polymorphize any closures/generators captured as upvars.
let upvars_ty = upvars_ty.unwrap();
let polymorphized_upvars_ty = upvars_ty.fold_with(
- &mut PolymorphizationFolder { tcx });
+ &mut PolymorphizationFolder { tcx }).into_ok();
debug!("polymorphize: polymorphized_upvars_ty={:?}", polymorphized_upvars_ty);
ty::GenericArg::from(polymorphized_upvars_ty)
},
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
+use crate::ty::normalize_erasing_regions::NormalizationError;
use crate::ty::subst::Subst;
use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
use rustc_ast as ast;
pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>),
SizeOverflow(Ty<'tcx>),
+ NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
}
impl<'tcx> fmt::Display for LayoutError<'tcx> {
LayoutError::SizeOverflow(ty) => {
write!(f, "values of the type `{}` are too big for the current architecture", ty)
}
+ LayoutError::NormalizationFailure(t, e) => write!(
+ f,
+ "unable to determine layout for `{}` because `{}` cannot be normalized",
+ t,
+ e.get_type_for_failure()
+ ),
}
}
}
+#[instrument(skip(tcx, query), level = "debug")]
fn layout_of<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
ty::tls::with_related_context(tcx, move |icx| {
let (param_env, ty) = query.into_parts();
+ debug!(?ty);
if !tcx.recursion_limit().value_within_limit(icx.layout_depth) {
tcx.sess.fatal(&format!("overflow representing the type `{}`", ty));
ty::tls::enter_context(&icx, |_| {
let param_env = param_env.with_reveal_all_normalized(tcx);
let unnormalized_ty = ty;
- let ty = tcx.normalize_erasing_regions(param_env, ty);
+
+ // FIXME: We might want to have two different versions of `layout_of`:
+ // One that can be called after typecheck has completed and can use
+ // `normalize_erasing_regions` here and another one that can be called
+ // before typecheck has completed and uses `try_normalize_erasing_regions`.
+ let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
+ Ok(t) => t,
+ Err(normalization_error) => {
+ return Err(LayoutError::NormalizationFailure(ty, normalization_error));
+ }
+ };
+
if ty != unnormalized_ty {
// Ensure this layout is also cached for the normalized type.
return tcx.layout_of(param_env.and(ty));
}
impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
- fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder))
+ fn super_fold_with<F: ty::fold::TypeFolder<'tcx>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(ParamEnv::new(self.caller_bounds().fold_with(folder)?, self.reveal().fold_with(folder)?))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
//! or constant found within. (This underlying query is what is cached.)
use crate::mir;
+use crate::traits::query::NoSolution;
use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::ty::subst::{Subst, SubstsRef};
use crate::ty::{self, Ty, TyCtxt};
+#[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)]
+pub enum NormalizationError<'tcx> {
+ Type(Ty<'tcx>),
+ Const(ty::Const<'tcx>),
+ ConstantKind(mir::ConstantKind<'tcx>),
+}
+
+impl<'tcx> NormalizationError<'tcx> {
+ pub fn get_type_for_failure(&self) -> String {
+ match self {
+ NormalizationError::Type(t) => format!("{}", t),
+ NormalizationError::Const(c) => format!("{}", c),
+ NormalizationError::ConstantKind(ck) => format!("{}", ck),
+ }
+ }
+}
+
impl<'tcx> TyCtxt<'tcx> {
/// Erase the regions in `value` and then fully normalize all the
/// types found within. The result will also have regions erased.
// Erase first before we do the real query -- this keeps the
// cache from being too polluted.
let value = self.erase_regions(value);
+ debug!(?value);
+
if !value.has_projections() {
value
} else {
- value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
+ value
+ .fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env })
+ .into_ok()
+ }
+ }
+
+ /// Tries to erase the regions in `value` and then fully normalize all the
+ /// types found within. The result will also have regions erased.
+ ///
+ /// Contrary to `normalize_erasing_regions` this function does not assume that normalization
+ /// succeeds.
+ pub fn try_normalize_erasing_regions<T>(
+ self,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ ) -> Result<T, NormalizationError<'tcx>>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ debug!(
+ "try_normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
+ std::any::type_name::<T>(),
+ value,
+ param_env,
+ );
+
+ // Erase first before we do the real query -- this keeps the
+ // cache from being too polluted.
+ let value = self.erase_regions(value);
+ debug!(?value);
+
+ if !value.has_projections() {
+ Ok(value)
+ } else {
+ let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env);
+ value.fold_with(&mut folder)
}
}
}
impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
+ #[instrument(skip(self), level = "debug")]
fn normalize_generic_arg_after_erasing_regions(
&self,
arg: ty::GenericArg<'tcx>,
) -> ty::GenericArg<'tcx> {
let arg = self.param_env.and(arg);
+ debug!(?arg);
+
self.tcx.normalize_generic_arg_after_erasing_regions(arg)
}
}
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty()
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ Ok(self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty())
}
- fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
+ fn fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ Ok(self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const())
}
#[inline]
- fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ fn fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
// FIXME: This *probably* needs canonicalization too!
let arg = self.param_env.and(c);
- self.tcx.normalize_mir_const_after_erasing_regions(arg)
+ Ok(self.tcx.normalize_mir_const_after_erasing_regions(arg))
+ }
+}
+
+struct TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+ TryNormalizeAfterErasingRegionsFolder { tcx, param_env }
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn try_normalize_generic_arg_after_erasing_regions(
+ &self,
+ arg: ty::GenericArg<'tcx>,
+ ) -> Result<ty::GenericArg<'tcx>, NoSolution> {
+ let arg = self.param_env.and(arg);
+ debug!(?arg);
+
+ self.tcx.try_normalize_generic_arg_after_erasing_regions(arg)
+ }
+}
+
+impl TypeFolder<'tcx> for TryNormalizeAfterErasingRegionsFolder<'tcx> {
+ type Error = NormalizationError<'tcx>;
+
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ match self.try_normalize_generic_arg_after_erasing_regions(ty.into()) {
+ Ok(t) => Ok(t.expect_ty()),
+ Err(_) => Err(NormalizationError::Type(ty)),
+ }
+ }
+
+ fn fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
+ Ok(t) => Ok(t.expect_const()),
+ Err(_) => Err(NormalizationError::Const(*c)),
+ }
+ }
+
+ fn fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ // FIXME: This *probably* needs canonicalization too!
+ let arg = self.param_env.and(c);
+ match self.tcx.try_normalize_mir_const_after_erasing_regions(arg) {
+ Ok(c) => Ok(c),
+ Err(_) => Err(NormalizationError::ConstantKind(c)),
+ }
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> ty::Binder<'tcx, T> {
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *t.kind() {
_ if t.has_vars_bound_at_or_above(self.current_index) || t.has_placeholders() => {
return t.super_fold_with(self);
}
_ => {}
}
- t
+ Ok(t)
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
let name = &mut self.name;
let region = match *r {
ty::ReLateBound(_, br) => self.region_map.entry(br).or_insert_with(|| name(br)),
}
}
}
- _ => return r,
+ _ => return Ok(r),
};
if let ty::ReLateBound(debruijn1, br) = *region {
assert_eq!(debruijn1, ty::INNERMOST);
- self.tcx.mk_region(ty::ReLateBound(self.current_index, br))
+ Ok(self.tcx.mk_region(ty::ReLateBound(self.current_index, br)))
} else {
- region
+ Ok(region)
}
}
}
name: &mut name,
region_map: BTreeMap::new(),
};
- let new_value = value.clone().skip_binder().fold_with(&mut folder);
+ let new_value = value.clone().skip_binder().fold_with(&mut folder).into_ok();
let region_map = folder.region_map;
start_or_continue(&mut self, "", "> ");
(new_value, region_map)
/// AdtDefs are basically the same as a DefId.
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
- self
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (T, U) {
- (self.0.fold_with(folder), self.1.fold_with(folder))
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<(T, U), F::Error> {
+ Ok((self.0.fold_with(folder)?, self.1.fold_with(folder)?))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>> TypeFoldable<'tcx>
for (A, B, C)
{
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> (A, B, C) {
- (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder))
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<(A, B, C), F::Error> {
+ Ok((self.0.fold_with(folder)?, self.1.fold_with(folder)?, self.2.fold_with(folder)?))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
// FIXME: Reuse the `Rc` here.
- Rc::new((*self).clone().fold_with(folder))
+ Ok(Rc::new((*self).clone().fold_with(folder)?))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
// FIXME: Reuse the `Arc` here.
- Arc::new((*self).clone().fold_with(folder))
+ Ok(Arc::new((*self).clone().fold_with(folder)?))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|value| value.fold_with(folder))
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|value| value.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|t| t.fold_with(folder))
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|t| t.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|t| t.fold_with(folder))
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|t| t.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_bound(|ty| ty.fold_with(folder))
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_bound(|ty| ty.fold_with(folder))
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.fold_binder(self)
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v))
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v))
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
use crate::ty::InstanceDef::*;
- Self {
- substs: self.substs.fold_with(folder),
+ Ok(Self {
+ substs: self.substs.fold_with(folder)?,
def: match self.def {
- Item(def) => Item(def.fold_with(folder)),
- VtableShim(did) => VtableShim(did.fold_with(folder)),
- ReifyShim(did) => ReifyShim(did.fold_with(folder)),
- Intrinsic(did) => Intrinsic(did.fold_with(folder)),
- FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder), ty.fold_with(folder)),
- Virtual(did, i) => Virtual(did.fold_with(folder), i),
+ Item(def) => Item(def.fold_with(folder)?),
+ VtableShim(did) => VtableShim(did.fold_with(folder)?),
+ ReifyShim(did) => ReifyShim(did.fold_with(folder)?),
+ Intrinsic(did) => Intrinsic(did.fold_with(folder)?),
+ FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder)?, ty.fold_with(folder)?),
+ Virtual(did, i) => Virtual(did.fold_with(folder)?, i),
ClosureOnceShim { call_once, track_caller } => {
- ClosureOnceShim { call_once: call_once.fold_with(folder), track_caller }
+ ClosureOnceShim { call_once: call_once.fold_with(folder)?, track_caller }
}
- DropGlue(did, ty) => DropGlue(did.fold_with(folder), ty.fold_with(folder)),
- CloneShim(did, ty) => CloneShim(did.fold_with(folder), ty.fold_with(folder)),
+ DropGlue(did, ty) => DropGlue(did.fold_with(folder)?, ty.fold_with(folder)?),
+ CloneShim(did, ty) => CloneShim(did.fold_with(folder)?, ty.fold_with(folder)?),
},
- }
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- Self { instance: self.instance.fold_with(folder), promoted: self.promoted }
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(Self { instance: self.instance.fold_with(folder)?, promoted: self.promoted })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
let kind = match *self.kind() {
- ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)),
- ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)),
- ty::Slice(typ) => ty::Slice(typ.fold_with(folder)),
- ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)),
+ ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)?),
+ ty::Array(typ, sz) => ty::Array(typ.fold_with(folder)?, sz.fold_with(folder)?),
+ ty::Slice(typ) => ty::Slice(typ.fold_with(folder)?),
+ ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)?),
ty::Dynamic(trait_ty, region) => {
- ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder))
+ ty::Dynamic(trait_ty.fold_with(folder)?, region.fold_with(folder)?)
}
- ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)),
- ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)),
- ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)),
- ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl),
+ ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)?),
+ ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)?),
+ ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)?),
+ ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder)?, ty.fold_with(folder)?, mutbl),
ty::Generator(did, substs, movability) => {
- ty::Generator(did, substs.fold_with(folder), movability)
+ ty::Generator(did, substs.fold_with(folder)?, movability)
}
- ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)),
- ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)),
- ty::Projection(data) => ty::Projection(data.fold_with(folder)),
- ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)),
+ ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)?),
+ ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)?),
+ ty::Projection(data) => ty::Projection(data.fold_with(folder)?),
+ ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)?),
ty::Bool
| ty::Char
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Never
- | ty::Foreign(..) => return self,
+ | ty::Foreign(..) => return Ok(self),
};
- if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) }
+ Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) })
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.fold_ty(self)
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
- self
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.fold_region(self)
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.fold_predicate(self)
}
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- let new = self.inner.kind.fold_with(folder);
- folder.tcx().reuse_or_mk_predicate(self, new)
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ let new = self.inner.kind.fold_with(folder)?;
+ Ok(folder.tcx().reuse_or_mk_predicate(self, new))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
}
}
impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- self.map_id(|x| x.fold_with(folder))
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ self.try_map_id(|x| x.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- let ty = self.ty.fold_with(folder);
- let val = self.val.fold_with(folder);
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ let ty = self.ty.fold_with(folder)?;
+ let val = self.val.fold_with(folder)?;
if ty != self.ty || val != self.val {
- folder.tcx().mk_const(ty::Const { ty, val })
+ Ok(folder.tcx().mk_const(ty::Const { ty, val }))
} else {
- self
+ Ok(self)
}
}
- fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.fold_const(self)
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- match self {
- ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
- ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
- ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)),
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(match self {
+ ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)?),
+ ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)?),
+ ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)?),
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..)
| ty::ConstKind::Error(_) => self,
- }
+ })
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
- self
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
+ Ok(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- ty::Unevaluated {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(ty::Unevaluated {
def: self.def,
- substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
+ substs_: Some(self.substs(folder.tcx()).fold_with(folder)?),
promoted: self.promoted,
- }
+ })
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
}
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- ty::Unevaluated {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(ty::Unevaluated {
def: self.def,
- substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
+ substs_: Some(self.substs(folder.tcx()).fold_with(folder)?),
promoted: self.promoted,
- }
+ })
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
Binder(value, self.1)
}
+ pub fn try_map_bound<F, U: TypeFoldable<'tcx>, E>(self, f: F) -> Result<Binder<'tcx, U>, E>
+ where
+ F: FnOnce(T) -> Result<U, E>,
+ {
+ let value = f(self.0)?;
+ if cfg!(debug_assertions) {
+ let mut validator = ValidateBoundVars::new(self.1);
+ value.visit_with(&mut validator);
+ }
+ Ok(Binder(value, self.1))
+ }
+
/// Wraps a `value` in a binder, using the same bound variables as the
/// current `Binder`. This should not be used if the new value *changes*
/// the bound variables. Note: the (old or new) value itself does not
}
impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
match self.unpack() {
- GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(),
- GenericArgKind::Type(ty) => ty.fold_with(folder).into(),
- GenericArgKind::Const(ct) => ct.fold_with(folder).into(),
+ GenericArgKind::Lifetime(lt) => lt.fold_with(folder).map(Into::into),
+ GenericArgKind::Type(ty) => ty.fold_with(folder).map(Into::into),
+ GenericArgKind::Const(ct) => ct.fold_with(folder).map(Into::into),
}
}
}
impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
- fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
// This code is hot enough that it's worth specializing for the most
// common length lists, to avoid the overhead of `SmallVec` creation.
// The match arms are in order of frequency. The 1, 2, and 0 cases are
// calling `intern_substs`.
match self.len() {
1 => {
- let param0 = self[0].fold_with(folder);
- if param0 == self[0] { self } else { folder.tcx().intern_substs(&[param0]) }
+ let param0 = self[0].fold_with(folder)?;
+ if param0 == self[0] { Ok(self) } else { Ok(folder.tcx().intern_substs(&[param0])) }
}
2 => {
- let param0 = self[0].fold_with(folder);
- let param1 = self[1].fold_with(folder);
+ let param0 = self[0].fold_with(folder)?;
+ let param1 = self[1].fold_with(folder)?;
if param0 == self[0] && param1 == self[1] {
- self
+ Ok(self)
} else {
- folder.tcx().intern_substs(&[param0, param1])
+ Ok(folder.tcx().intern_substs(&[param0, param1]))
}
}
- 0 => self,
+ 0 => Ok(self),
_ => {
- let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect();
- if params[..] == self[..] { self } else { folder.tcx().intern_substs(¶ms) }
+ let params: SmallVec<[_; 8]> =
+ self.iter().map(|k| k.fold_with(folder)).collect::<Result<_, _>>()?;
+ if params[..] == self[..] {
+ Ok(self)
+ } else {
+ Ok(folder.tcx().intern_substs(¶ms))
+ }
}
}
}
span: Option<Span>,
) -> T {
let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 };
- self.fold_with(&mut folder)
+ self.fold_with(&mut folder).into_ok()
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> ty::Binder<'tcx, T> {
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.binders_passed += 1;
- let t = t.super_fold_with(self);
+ let t = t.super_fold_with(self)?;
self.binders_passed -= 1;
- t
+ Ok(t)
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
// Note: This routine only handles regions that are bound on
// type declarations and other outer declarations, not those
// bound in *fn types*. Region substitution of the bound
ty::ReEarlyBound(data) => {
let rk = self.substs.get(data.index as usize).map(|k| k.unpack());
match rk {
- Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt),
+ Some(GenericArgKind::Lifetime(lt)) => Ok(self.shift_region_through_binders(lt)),
_ => {
let span = self.span.unwrap_or(DUMMY_SP);
let msg = format!(
}
}
}
- _ => r,
+ _ => Ok(r),
}
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !t.potentially_needs_subst() {
- return t;
+ return Ok(t);
}
match *t.kind() {
- ty::Param(p) => self.ty_for_param(p, t),
+ ty::Param(p) => Ok(self.ty_for_param(p, t)),
_ => t.super_fold_with(self),
}
}
- fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ c: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if let ty::ConstKind::Param(p) = c.val {
- self.const_for_param(p, c)
+ Ok(self.const_for_param(p, c))
} else {
c.super_fold_with(self)
}
}
#[inline]
- fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ fn fold_mir_const(
+ &mut self,
+ c: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
c.super_fold_with(self)
}
}
if self.found_any_recursion {
return None;
}
- let substs = substs.fold_with(self);
+ let substs = substs.fold_with(self).into_ok();
if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
Some(expanded_ty) => expanded_ty,
None => {
let generic_ty = self.tcx.type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx, substs);
- let expanded_ty = self.fold_ty(concrete_ty);
+ let expanded_ty = self.fold_ty(concrete_ty).into_ok();
self.expanded_cache.insert((def_id, substs), expanded_ty);
expanded_ty
}
self.tcx
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if let ty::Opaque(def_id, substs) = t.kind {
- self.expand_opaque_ty(def_id, substs).unwrap_or(t)
+ Ok(self.expand_opaque_ty(def_id, substs).unwrap_or(t))
} else if t.has_opaque_types() {
t.super_fold_with(self)
} else {
- t
+ Ok(t)
}
}
}
list: &'tcx ty::List<T>,
folder: &mut F,
intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
-) -> &'tcx ty::List<T>
+) -> Result<&'tcx ty::List<T>, F::Error>
where
F: TypeFolder<'tcx>,
T: TypeFoldable<'tcx> + PartialEq + Copy,
{
let mut iter = list.iter();
// Look for the first element that changed
- if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| {
- let new_t = t.fold_with(folder);
- if new_t == t { None } else { Some((i, new_t)) }
+ match iter.by_ref().enumerate().find_map(|(i, t)| match t.fold_with(folder) {
+ Ok(new_t) if new_t == t => None,
+ new_t => Some((i, new_t)),
}) {
- // An element changed, prepare to intern the resulting list
- let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
- new_list.extend_from_slice(&list[..i]);
- new_list.push(new_t);
- new_list.extend(iter.map(|t| t.fold_with(folder)));
- intern(folder.tcx(), &new_list)
- } else {
- list
+ Some((i, Ok(new_t))) => {
+ // An element changed, prepare to intern the resulting list
+ let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
+ new_list.extend_from_slice(&list[..i]);
+ new_list.push(new_t);
+ for t in iter {
+ new_list.push(t.fold_with(folder)?)
+ }
+ Ok(intern(folder.tcx(), &new_list))
+ }
+ Some((_, Err(err))) => {
+ return Err(err);
+ }
+ None => Ok(list),
}
}
check_recursion: false,
tcx,
};
- val.fold_with(&mut visitor)
+ val.fold_with(&mut visitor).into_ok()
}
pub fn provide(providers: &mut ty::query::Providers) {
}
}
- fn process_projection_elem(
- &mut self,
- elem: PlaceElem<'tcx>,
- _: Location,
- ) -> Option<PlaceElem<'tcx>> {
- match elem {
- PlaceElem::Index(local) => {
- if let Some(replacement) = self.replacements.for_src(local) {
- bug!(
- "cannot replace {:?} with {:?} in index projection {:?}",
- local,
- replacement,
- elem,
- );
- } else {
- None
- }
- }
- _ => None,
- }
- }
-
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
if let Some(replacement) = self.replacements.for_src(place.local) {
// Rebase `place`s projections onto `replacement`'s.
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::Visitor as _;
-use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPhase, Promoted};
+use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_span::{Span, Symbol};
use rustc_const_eval::transform::check_consts;
use rustc_const_eval::transform::promote_consts;
use rustc_const_eval::transform::validate;
-pub use rustc_const_eval::transform::MirPass;
use rustc_mir_dataflow::rustc_peek;
pub fn provide(providers: &mut Providers) {
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
*ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
}
-
- #[inline]
- fn process_projection_elem(
- &mut self,
- elem: PlaceElem<'tcx>,
- _: Location,
- ) -> Option<PlaceElem<'tcx>> {
- match elem {
- PlaceElem::Field(field, ty) => {
- let new_ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
- if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
- }
- // None of those contain a Ty.
- PlaceElem::Index(..)
- | PlaceElem::Deref
- | PlaceElem::ConstantIndex { .. }
- | PlaceElem::Subslice { .. }
- | PlaceElem::Downcast(..) => None,
- }
- }
}
+use super::pat::Expected;
use super::ty::AllowPlus;
-use super::TokenType;
-use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType};
+use super::{
+ BlockMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, SemiColonMode, SeqSep,
+ TokenExpectType, TokenType,
+};
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP};
+use std::mem::take;
+
use tracing::{debug, trace};
const TURBOFISH_SUGGESTION_STR: &str =
);
err
}
+
+ /// Some special error handling for the "top-level" patterns in a match arm,
+ /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
+ crate fn maybe_recover_colon_colon_in_pat_typo(
+ &mut self,
+ mut first_pat: P<Pat>,
+ ra: RecoverColon,
+ expected: Expected,
+ ) -> P<Pat> {
+ if RecoverColon::Yes != ra || token::Colon != self.token.kind {
+ return first_pat;
+ }
+ if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
+ || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
+ {
+ return first_pat;
+ }
+ // The pattern looks like it might be a path with a `::` -> `:` typo:
+ // `match foo { bar:baz => {} }`
+ let span = self.token.span;
+ // We only emit "unexpected `:`" error here if we can successfully parse the
+ // whole pattern correctly in that case.
+ let snapshot = self.clone();
+
+ // Create error for "unexpected `:`".
+ match self.expected_one_of_not_found(&[], &[]) {
+ Err(mut err) => {
+ self.bump(); // Skip the `:`.
+ match self.parse_pat_no_top_alt(expected) {
+ Err(mut inner_err) => {
+ // Carry on as if we had not done anything, callers will emit a
+ // reasonable error.
+ inner_err.cancel();
+ err.cancel();
+ *self = snapshot;
+ }
+ Ok(mut pat) => {
+ // We've parsed the rest of the pattern.
+ let new_span = first_pat.span.to(pat.span);
+ let mut show_sugg = false;
+ // Try to construct a recovered pattern.
+ match &mut pat.kind {
+ PatKind::Struct(qself @ None, path, ..)
+ | PatKind::TupleStruct(qself @ None, path, _)
+ | PatKind::Path(qself @ None, path) => match &first_pat.kind {
+ PatKind::Ident(_, ident, _) => {
+ path.segments.insert(0, PathSegment::from_ident(ident.clone()));
+ path.span = new_span;
+ show_sugg = true;
+ first_pat = pat;
+ }
+ PatKind::Path(old_qself, old_path) => {
+ path.segments = old_path
+ .segments
+ .iter()
+ .cloned()
+ .chain(take(&mut path.segments))
+ .collect();
+ path.span = new_span;
+ *qself = old_qself.clone();
+ first_pat = pat;
+ show_sugg = true;
+ }
+ _ => {}
+ },
+ PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => {
+ match &first_pat.kind {
+ PatKind::Ident(_, old_ident, _) => {
+ let path = PatKind::Path(
+ None,
+ Path {
+ span: new_span,
+ segments: vec![
+ PathSegment::from_ident(old_ident.clone()),
+ PathSegment::from_ident(ident.clone()),
+ ],
+ tokens: None,
+ },
+ );
+ first_pat = self.mk_pat(new_span, path);
+ show_sugg = true;
+ }
+ PatKind::Path(old_qself, old_path) => {
+ let mut segments = old_path.segments.clone();
+ segments.push(PathSegment::from_ident(ident.clone()));
+ let path = PatKind::Path(
+ old_qself.clone(),
+ Path { span: new_span, segments, tokens: None },
+ );
+ first_pat = self.mk_pat(new_span, path);
+ show_sugg = true;
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ if show_sugg {
+ err.span_suggestion(
+ span,
+ "maybe write a path separator here",
+ "::".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ first_pat = self.mk_pat(new_span, PatKind::Wild);
+ }
+ err.emit();
+ }
+ }
+ }
+ _ => {
+ // Carry on as if we had not done anything. This should be unreachable.
+ *self = snapshot;
+ }
+ };
+ first_pat
+ }
+
+ /// Some special error handling for the "top-level" patterns in a match arm,
+ /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
+ crate fn maybe_recover_unexpected_comma(
+ &mut self,
+ lo: Span,
+ rc: RecoverComma,
+ ) -> PResult<'a, ()> {
+ if rc == RecoverComma::No || self.token != token::Comma {
+ return Ok(());
+ }
+
+ // An unexpected comma after a top-level pattern is a clue that the
+ // user (perhaps more accustomed to some other language) forgot the
+ // parentheses in what should have been a tuple pattern; return a
+ // suggestion-enhanced error here rather than choking on the comma later.
+ let comma_span = self.token.span;
+ self.bump();
+ if let Err(mut err) = self.skip_pat_list() {
+ // We didn't expect this to work anyway; we just wanted to advance to the
+ // end of the comma-sequence so we know the span to suggest parenthesizing.
+ err.cancel();
+ }
+ let seq_span = lo.to(self.prev_token.span);
+ let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
+ if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
+ const MSG: &str = "try adding parentheses to match on a tuple...";
+
+ err.span_suggestion(
+ seq_span,
+ MSG,
+ format!("({})", seq_snippet),
+ Applicability::MachineApplicable,
+ );
+ err.span_suggestion(
+ seq_span,
+ "...or a vertical bar to match on multiple alternatives",
+ seq_snippet.replace(",", " |"),
+ Applicability::MachineApplicable,
+ );
+ }
+ Err(err)
+ }
+
+ /// Parse and throw away a parenthesized comma separated
+ /// sequence of patterns until `)` is reached.
+ fn skip_pat_list(&mut self) -> PResult<'a, ()> {
+ while !self.check(&token::CloseDelim(token::Paren)) {
+ self.parse_pat_no_top_alt(None)?;
+ if !self.eat(&token::Comma) {
+ return Ok(());
+ }
+ }
+ Ok(())
+ }
}
use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
use rustc_ast::ptr::P;
use rustc_ast::token;
-use rustc_ast::{self as ast, AttrVec, Attribute, MacCall, Pat, PatField, PatKind, RangeEnd};
-use rustc_ast::{BindingMode, Expr, ExprKind, Mutability, Path, QSelf, RangeSyntax};
+use rustc_ast::{
+ self as ast, AttrVec, Attribute, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat,
+ PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
+};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult};
use rustc_span::source_map::{respan, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident};
-type Expected = Option<&'static str>;
+pub(super) type Expected = Option<&'static str>;
/// `Expected` for function and lambda parameter patterns.
pub(super) const PARAM_EXPECTED: Expected = Some("parameter name");
// If we parsed a leading `|` which should be gated,
// then we should really gate the leading `|`.
// This complicated procedure is done purely for diagnostics UX.
- let mut first_pat = first_pat;
-
- if let (RecoverColon::Yes, token::Colon) = (ra, &self.token.kind) {
- if matches!(
- first_pat.kind,
- PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None)
- | PatKind::Path(..)
- ) && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
- {
- // The pattern looks like it might be a path with a `::` -> `:` typo:
- // `match foo { bar:baz => {} }`
- let span = self.token.span;
- // We only emit "unexpected `:`" error here if we can successfully parse the
- // whole pattern correctly in that case.
- let snapshot = self.clone();
-
- // Create error for "unexpected `:`".
- match self.expected_one_of_not_found(&[], &[]) {
- Err(mut err) => {
- self.bump(); // Skip the `:`.
- match self.parse_pat_no_top_alt(expected) {
- Err(mut inner_err) => {
- // Carry on as if we had not done anything, callers will emit a
- // reasonable error.
- inner_err.cancel();
- err.cancel();
- *self = snapshot;
- }
- Ok(pat) => {
- // We've parsed the rest of the pattern.
- err.span_suggestion(
- span,
- "maybe write a path separator here",
- "::".to_string(),
- Applicability::MachineApplicable,
- );
- err.emit();
- first_pat =
- self.mk_pat(first_pat.span.to(pat.span), PatKind::Wild);
- }
- }
- }
- _ => {
- // Carry on as if we had not done anything. This should be unreachable.
- *self = snapshot;
- }
- };
- }
- }
+
+ // Check if the user wrote `foo:bar` instead of `foo::bar`.
+ let first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, ra, expected);
if let Some(leading_vert_span) = leading_vert_span {
// If there was a leading vert, treat this as an or-pattern. This improves
err.emit();
}
- /// Some special error handling for the "top-level" patterns in a match arm,
- /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
- fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> {
- if rc == RecoverComma::No || self.token != token::Comma {
- return Ok(());
- }
-
- // An unexpected comma after a top-level pattern is a clue that the
- // user (perhaps more accustomed to some other language) forgot the
- // parentheses in what should have been a tuple pattern; return a
- // suggestion-enhanced error here rather than choking on the comma later.
- let comma_span = self.token.span;
- self.bump();
- if let Err(mut err) = self.skip_pat_list() {
- // We didn't expect this to work anyway; we just wanted to advance to the
- // end of the comma-sequence so we know the span to suggest parenthesizing.
- err.cancel();
- }
- let seq_span = lo.to(self.prev_token.span);
- let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
- if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
- const MSG: &str = "try adding parentheses to match on a tuple...";
-
- err.span_suggestion(
- seq_span,
- MSG,
- format!("({})", seq_snippet),
- Applicability::MachineApplicable,
- );
- err.span_suggestion(
- seq_span,
- "...or a vertical bar to match on multiple alternatives",
- seq_snippet.replace(",", " |"),
- Applicability::MachineApplicable,
- );
- }
- Err(err)
- }
-
- /// Parse and throw away a parenthesized comma separated
- /// sequence of patterns until `)` is reached.
- fn skip_pat_list(&mut self) -> PResult<'a, ()> {
- while !self.check(&token::CloseDelim(token::Paren)) {
- self.parse_pat_no_top_alt(None)?;
- if !self.eat(&token::Comma) {
- return Ok(());
- }
- }
- Ok(())
- }
-
/// A `|` or possibly `||` token shouldn't be here. Ban it.
fn ban_illegal_vert(&mut self, lo: Option<Span>, pos: &str, ctx: &str) {
let span = self.token.span;
self.mk_pat(span, PatKind::Ident(bm, ident, None))
}
- fn mk_pat(&self, span: Span, kind: PatKind) -> P<Pat> {
+ pub(super) fn mk_pat(&self, span: Span, kind: PatKind) -> P<Pat> {
P(Pat { kind, span, id: ast::DUMMY_NODE_ID, tokens: None })
}
}
match impl_item.kind {
hir::ImplItemKind::Const(..) => Target::AssocConst,
hir::ImplItemKind::Fn(..) => {
- let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id()).expect_owner();
let containing_item = tcx.hir().expect_item(parent_hir_id);
let containing_impl_is_for_trait = match &containing_item.kind {
hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
Target::Impl => Some("implementation block"),
Target::ForeignMod => Some("extern block"),
Target::AssocTy => {
- let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
+ let parent_hir_id = self.tcx.hir().get_parent_item(hir_id).expect_owner();
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
if Target::from_item(containing_item) == Target::Impl {
Some("type alias in implementation block")
}
}
Target::AssocConst => {
- let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
+ let parent_hir_id = self.tcx.hir().get_parent_item(hir_id).expect_owner();
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
// We can't link to trait impl's consts.
let err = "associated constant in trait implementation block";
}
}
-fn get_lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures {
+fn lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures {
let mut collector = LibFeatureCollector::new(tcx);
tcx.hir().walk_attributes(&mut collector);
collector.lib_features
}
pub fn provide(providers: &mut Providers) {
- providers.get_lib_features = get_lib_features;
+ providers.lib_features = lib_features;
}
// Check the impl. If the generics on the self
// type of the impl require inlining, this method
// does too.
- let impl_hir_id = self.tcx.hir().local_def_id_to_hir_id(impl_did);
- match self.tcx.hir().expect_item(impl_hir_id).kind {
+ match self.tcx.hir().expect_item(impl_did).kind {
hir::ItemKind::Impl { .. } => {
let generics = self.tcx.generics_of(impl_did);
generics.requires_monomorphization(self.tcx)
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{Arm, Block, Expr, Local, Node, Pat, PatKind, Stmt};
+use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
use rustc_index::vec::Idx;
use rustc_middle::middle::region::*;
use rustc_middle::ty::query::Providers;
let body = tcx.hir().body(body_id);
visitor.scope_tree.root_body = Some(body.value.hir_id);
-
- // If the item is an associated const or a method,
- // record its impl/trait parent, as it can also have
- // lifetime parameters free in this body.
- match tcx.hir().get(id) {
- Node::ImplItem(_) | Node::TraitItem(_) => {
- visitor.scope_tree.root_parent = Some(tcx.hir().get_parent_item(id));
- }
- _ => {}
- }
-
visitor.visit_body(body);
-
visitor.scope_tree
} else {
ScopeTree::default()
// We always collect the lib features declared in the current crate, even if there are
// no unknown features, because the collection also does feature attribute validation.
- let local_defined_features = tcx.lib_features().to_vec();
+ let local_defined_features = tcx.lib_features(()).to_vec();
if !remaining_lib_features.is_empty() {
check_features(&mut remaining_lib_features, &local_defined_features);
// have normal hygine, so we can treat them like other items without type
// privacy and mark them reachable.
DefKind::Macro(_) => {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let item = self.tcx.hir().expect_item(hir_id);
+ let item = self.tcx.hir().expect_item(def_id);
if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }) = item.kind {
if vis.is_accessible_from(module.to_def_id(), self.tcx) {
self.update(def_id, level);
DefKind::Struct | DefKind::Union => {
// While structs and unions have type privacy, their fields do not.
if vis.is_public() {
- let item =
- self.tcx.hir().expect_item(self.tcx.hir().local_def_id_to_hir_id(def_id));
+ let item = self.tcx.hir().expect_item(def_id);
if let hir::ItemKind::Struct(ref struct_def, _)
| hir::ItemKind::Union(ref struct_def, _) = item.kind
{
// If the module is `self`, i.e. the current crate,
// there will be no corresponding item.
.filter(|def_id| def_id.index != CRATE_DEF_INDEX || def_id.krate != LOCAL_CRATE)
- .and_then(|def_id| {
- def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
- })
+ .and_then(|def_id| def_id.as_local())
.map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id))
{
if let hir::ItemKind::Mod(m) = &item.kind {
fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
let res = b.res();
- if b.span.is_dummy() {
+ if b.span.is_dummy() || self.session.source_map().span_to_snippet(b.span).is_err() {
// These already contain the "built-in" prefix or look bad with it.
let add_built_in =
!matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
trait_definition_only: bool,
with_scope_for_path: bool,
) -> NamedRegionMap {
- let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(local_def_id));
+ let item = tcx.hir().expect_item(local_def_id);
let mut named_region_map = NamedRegionMap {
defs: Default::default(),
late_bound: Default::default(),
self.missing_named_lifetime_spots.push((&trait_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
- Some(tcx.hir().get_parent_item(trait_item.hir_id())),
+ Some(tcx.hir().get_parent_did(trait_item.hir_id())),
trait_item.hir_id(),
&sig.decl,
&trait_item.generics,
self.missing_named_lifetime_spots.push((&impl_item.generics).into());
let tcx = self.tcx;
self.visit_early_late(
- Some(tcx.hir().get_parent_item(impl_item.hir_id())),
+ Some(tcx.hir().get_parent_did(impl_item.hir_id())),
impl_item.hir_id(),
&sig.decl,
&impl_item.generics,
/// ordering is not important there.
fn visit_early_late<F>(
&mut self,
- parent_id: Option<hir::HirId>,
+ parent_id: Option<LocalDefId>,
hir_id: hir::HirId,
decl: &'tcx hir::FnDecl<'tcx>,
generics: &'tcx hir::Generics<'tcx>,
Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(_, ref m), .. }) => {
if let hir::ItemKind::Trait(.., ref trait_items) =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(parent)).kind
{
assoc_item_kind =
trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind);
Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => {
if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(parent)).kind
{
impl_self = Some(self_ty);
assoc_item_kind =
}
pub fn next_node_id(&mut self) -> NodeId {
- let next = self
- .next_node_id
- .as_usize()
- .checked_add(1)
- .expect("input too large; ran out of NodeIds");
- self.next_node_id = ast::NodeId::from_usize(next);
+ let next =
+ self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
+ self.next_node_id = ast::NodeId::from_u32(next);
self.next_node_id
}
Passes::All => false,
}
}
+
+ pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
+ match *self {
+ Passes::Some(ref mut v) => v.extend(passes),
+ Passes::All => {}
+ }
+ }
}
pub const fn default_lib_output() -> CrateType {
v => {
let mut passes = vec![];
if parse_list(&mut passes, v) {
- *slot = Passes::Some(passes);
+ slot.extend(passes);
true
} else {
false
HygieneData::with(|data| data.expn_data(self).clone())
}
+ #[inline]
pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
+ // a few "fast path" cases to avoid locking HygieneData
+ if ancestor == ExpnId::root() || ancestor == self {
+ return true;
+ }
+ if ancestor.krate != self.krate {
+ return false;
+ }
HygieneData::with(|data| data.is_descendant_of(self, ancestor))
}
}
fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
- while expn_id != ancestor {
+ // a couple "fast path" cases to avoid traversing parents in the loop below
+ if ancestor == ExpnId::root() {
+ return true;
+ }
+ if expn_id.krate != ancestor.krate {
+ return false;
+ }
+ loop {
+ if expn_id == ancestor {
+ return true;
+ }
if expn_id == ExpnId::root() {
return false;
}
expn_id = self.expn_data(expn_id).parent;
}
- true
}
fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
data: ExpnData,
hash: ExpnHash,
) -> ExpnId {
+ debug_assert!(data.parent == ExpnId::root() || krate == data.parent.krate);
let expn_id = ExpnId { krate, local_id };
HygieneData::with(|hygiene_data| {
let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data);
#![feature(never_type)]
#![feature(crate_visibility_modifier)]
#![feature(control_flow_enum)]
+#![feature(unwrap_infallible)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]
// Convert the type from the function into a type valid outside
// the function, by replacing invalid regions with 'static,
// after producing an error for each of them.
- let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new(
- self.tcx,
- self.is_tainted_by_errors(),
- def_id,
- map,
- instantiated_ty,
- span,
- ));
+ let definition_ty = instantiated_ty
+ .fold_with(&mut ReverseMapper::new(
+ self.tcx,
+ self.is_tainted_by_errors(),
+ def_id,
+ map,
+ instantiated_ty,
+ span,
+ ))
+ .into_ok();
debug!(?definition_ty);
definition_ty
) -> GenericArg<'tcx> {
assert!(!self.map_missing_regions_to_empty);
self.map_missing_regions_to_empty = true;
- let kind = kind.fold_with(self);
+ let kind = kind.fold_with(self).into_ok();
self.map_missing_regions_to_empty = false;
kind
}
fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
assert!(!self.map_missing_regions_to_empty);
- kind.fold_with(self)
+ kind.fold_with(self).into_ok()
}
}
}
#[instrument(skip(self), level = "debug")]
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match r {
// Ignore bound regions and `'static` regions that appear in the
// type, we only need to remap regions that reference lifetimes
// from the function declaraion.
// This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
- ty::ReLateBound(..) | ty::ReStatic => return r,
+ ty::ReLateBound(..) | ty::ReStatic => return Ok(r),
// If regions have been erased (by writeback), don't try to unerase
// them.
- ty::ReErased => return r,
+ ty::ReErased => return Ok(r),
// The regions that we expect from borrow checking.
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
let generics = self.tcx().generics_of(self.opaque_type_def_id);
match self.map.get(&r.into()).map(|k| k.unpack()) {
- Some(GenericArgKind::Lifetime(r1)) => r1,
+ Some(GenericArgKind::Lifetime(r1)) => Ok(r1),
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
None if self.map_missing_regions_to_empty || self.tainted_by_errors => {
- self.tcx.lifetimes.re_root_empty
+ Ok(self.tcx.lifetimes.re_root_empty)
}
None if generics.parent.is_some() => {
if let Some(hidden_ty) = self.hidden_ty.take() {
)
.emit();
}
- self.tcx.lifetimes.re_root_empty
+ Ok(self.tcx.lifetimes.re_root_empty)
}
None => {
self.tcx
)
.emit();
- self.tcx().lifetimes.re_static
+ Ok(self.tcx().lifetimes.re_static)
}
}
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *ty.kind() {
ty::Closure(def_id, substs) => {
// I am a horrible monster and I pray for death. When
}
}));
- self.tcx.mk_closure(def_id, substs)
+ Ok(self.tcx.mk_closure(def_id, substs))
}
ty::Generator(def_id, substs, movability) => {
}
}));
- self.tcx.mk_generator(def_id, substs, movability)
+ Ok(self.tcx.mk_generator(def_id, substs, movability))
}
ty::Param(param) => {
match self.map.get(&ty.into()).map(|k| k.unpack()) {
// Found it in the substitution list; replace with the parameter from the
// opaque type.
- Some(GenericArgKind::Type(t1)) => t1,
+ Some(GenericArgKind::Type(t1)) => Ok(t1),
Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
None => {
debug!(?param, ?self.map);
)
.emit();
- self.tcx().ty_error()
+ Ok(self.tcx().ty_error())
}
}
}
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
trace!("checking const {:?}", ct);
// Find a const parameter
- match ct.val {
+ Ok(match ct.val {
ty::ConstKind::Param(..) => {
// Look it up in the substitution list.
match self.map.get(&ct.into()).map(|k| k.unpack()) {
}
_ => ct,
- }
+ })
}
}
self.tcx
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- (match r {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ Ok((match r {
ty::ReVar(vid) => self.vid_to_region.get(vid).cloned(),
_ => None,
})
- .unwrap_or_else(|| r.super_fold_with(self))
+ .unwrap_or_else(|| r.super_fold_with(self).into_ok()))
}
}
// is otherwise overwhelming and unhelpful (see #85844 for an
// example).
- let trait_is_debug =
- self.tcx.is_diagnostic_item(sym::Debug, trait_ref.def_id());
- let trait_is_display =
- self.tcx.is_diagnostic_item(sym::Display, trait_ref.def_id());
-
let in_std_macro =
match obligation.cause.span.ctxt().outer_expn_data().macro_def_id {
Some(macro_def_id) => {
None => false,
};
- if in_std_macro && (trait_is_debug || trait_is_display) {
+ if in_std_macro
+ && matches!(
+ self.tcx.get_diagnostic_name(trait_ref.def_id()),
+ Some(sym::Debug | sym::Display)
+ )
+ {
err.emit();
return;
}
self.infcx.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() {
let infcx = self.infcx;
- self.var_map.entry(ty).or_insert_with(|| {
+ Ok(self.var_map.entry(ty).or_insert_with(|| {
infcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
span: DUMMY_SP,
})
- })
+ }))
} else {
ty.super_fold_with(self)
}
self.probe(|_| {
let mut selcx = SelectionContext::new(self);
- let cleaned_pred =
- pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() });
+ let cleaned_pred = pred
+ .fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() })
+ .into_ok();
let cleaned_pred = super::project::normalize(
&mut selcx,
if !needs_normalization(&value, self.param_env.reveal()) {
value
} else {
- value.fold_with(self)
+ value.fold_with(self).into_ok()
}
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> ty::Binder<'tcx, T> {
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.universes.push(None);
let t = t.super_fold_with(self);
self.universes.pop();
t
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !needs_normalization(&ty, self.param_env.reveal()) {
- return ty;
+ return Ok(ty);
}
// We try to be a little clever here as a performance optimization in
// replace bound vars if the current type is a `Projection` and we need
// to make sure we don't forget to fold the substs regardless.
- match *ty.kind() {
+ Ok(match *ty.kind() {
// This is really important. While we *can* handle this, this has
// severe performance implications for large opaque types with
// late-bound regions. See `issue-88862` benchmark.
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
- Reveal::UserFacing => ty.super_fold_with(self),
+ Reveal::UserFacing => ty.super_fold_with(self)?,
Reveal::All => {
let recursion_limit = self.tcx().recursion_limit();
self.selcx.infcx().report_overflow_error(&obligation, true);
}
- let substs = substs.super_fold_with(self);
+ let substs = substs.super_fold_with(self)?;
let generic_ty = self.tcx().type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.depth += 1;
- let folded_ty = self.fold_ty(concrete_ty);
+ let folded_ty = self.fold_ty(concrete_ty)?;
self.depth -= 1;
folded_ty
}
// register an obligation to *later* project, since we know
// there won't be bound vars there.
- let data = data.super_fold_with(self);
+ let data = data.super_fold_with(self)?;
let normalized_ty = normalize_projection_type(
self.selcx,
self.param_env,
let infcx = self.selcx.infcx();
let (data, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
- let data = data.super_fold_with(self);
+ let data = data.super_fold_with(self)?;
let normalized_ty = opt_normalize_projection_type(
self.selcx,
self.param_env,
.ok()
.flatten()
.map(|normalized_ty| {
- PlaceholderReplacer::replace_placeholders(
- infcx,
- mapped_regions,
- mapped_types,
- mapped_consts,
- &self.universes,
- normalized_ty,
- )
+ Ok({
+ PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ normalized_ty,
+ )
+ })
})
- .unwrap_or_else(|| ty.super_fold_with(self));
+ .unwrap_or_else(|| ty.super_fold_with(self))?;
debug!(
?self.depth,
normalized_ty
}
- _ => ty.super_fold_with(self),
- }
+ _ => ty.super_fold_with(self)?,
+ })
}
- fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ constant: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if self.selcx.tcx().lazy_normalization() {
- constant
+ Ok(constant)
} else {
- let constant = constant.super_fold_with(self);
- constant.eval(self.selcx.tcx(), self.param_env)
+ let constant = constant.super_fold_with(self)?;
+ Ok(constant.eval(self.selcx.tcx(), self.param_env))
}
}
}
universe_indices,
};
- let value = value.super_fold_with(&mut replacer);
+ let value = value.super_fold_with(&mut replacer).into_ok();
(value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> ty::Binder<'tcx, T> {
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
self.current_index.shift_out(1);
t
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
match *r {
ty::ReLateBound(debruijn, _)
if debruijn.as_usize() + 1
let universe = self.universe_for(debruijn);
let p = ty::PlaceholderRegion { universe, name: br.kind };
self.mapped_regions.insert(p, br);
- self.infcx.tcx.mk_region(ty::RePlaceholder(p))
+ Ok(self.infcx.tcx.mk_region(ty::RePlaceholder(p)))
}
- _ => r,
+ _ => Ok(r),
}
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *t.kind() {
ty::Bound(debruijn, _)
if debruijn.as_usize() + 1
let universe = self.universe_for(debruijn);
let p = ty::PlaceholderType { universe, name: bound_ty.var };
self.mapped_types.insert(p, bound_ty);
- self.infcx.tcx.mk_ty(ty::Placeholder(p))
+ Ok(self.infcx.tcx.mk_ty(ty::Placeholder(p)))
}
_ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
- _ => t,
+ _ => Ok(t),
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
match *ct {
ty::Const { val: ty::ConstKind::Bound(debruijn, _), ty: _ }
if debruijn.as_usize() + 1
name: ty::BoundConst { var: bound_const, ty },
};
self.mapped_consts.insert(p, bound_const);
- self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty })
+ Ok(self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty }))
}
_ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
- _ => ct,
+ _ => Ok(ct),
}
}
}
universe_indices,
current_index: ty::INNERMOST,
};
- value.super_fold_with(&mut replacer)
+ value.super_fold_with(&mut replacer).into_ok()
}
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> ty::Binder<'tcx, T> {
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
if !t.has_placeholders() && !t.has_infer_regions() {
- return t;
+ return Ok(t);
}
self.current_index.shift_in(1);
let t = t.super_fold_with(self);
t
}
- fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r0: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
let r1 = match r0 {
ty::ReVar(_) => self
.infcx
debug!(?r0, ?r1, ?r2, "fold_region");
- r2
+ Ok(r2)
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *ty.kind() {
ty::Placeholder(p) => {
let replace_var = self.mapped_types.get(&p);
let db = ty::DebruijnIndex::from_usize(
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
);
- self.tcx().mk_ty(ty::Bound(db, *replace_var))
+ Ok(self.tcx().mk_ty(ty::Bound(db, *replace_var)))
}
- None => ty,
+ None => Ok(ty),
}
}
_ if ty.has_placeholders() || ty.has_infer_regions() => ty.super_fold_with(self),
- _ => ty,
+ _ => Ok(ty),
}
}
- fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
if let ty::Const { val: ty::ConstKind::Placeholder(p), ty } = *ct {
let replace_var = self.mapped_consts.get(&p);
match replace_var {
let db = ty::DebruijnIndex::from_usize(
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
);
- self.tcx()
- .mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty })
+ Ok(self
+ .tcx()
+ .mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty }))
}
- None => ct,
+ None => Ok(ct),
}
} else {
ct.super_fold_with(self)
// when possible for this to work. See `auto-trait-projection-recursion.rs`
// for a case where this matters.
if progress.ty.has_infer_regions() {
- progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty);
+ progress.ty =
+ OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty).into_ok();
}
progress
}
cause: self.cause,
param_env: self.param_env,
obligations: vec![],
- error: false,
cache: SsoHashMap::new(),
anon_depth: 0,
universes: vec![],
std::any::type_name::<T>(),
normalizer.obligations,
);
- if normalizer.error {
- Err(NoSolution)
- } else {
- Ok(Normalized { value: result, obligations: normalizer.obligations })
- }
+ result.map(|value| Normalized { value, obligations: normalizer.obligations })
}
}
param_env: ty::ParamEnv<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
- error: bool,
anon_depth: usize,
universes: Vec<Option<ty::UniverseIndex>>,
}
impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
+ type Error = NoSolution;
+
fn tcx<'c>(&'c self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn fold_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: ty::Binder<'tcx, T>,
- ) -> ty::Binder<'tcx, T> {
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
self.universes.push(None);
let t = t.super_fold_with(self);
self.universes.pop();
}
#[instrument(level = "debug", skip(self))]
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !needs_normalization(&ty, self.param_env.reveal()) {
- return ty;
+ return Ok(ty);
}
if let Some(ty) = self.cache.get(&ty) {
- return ty;
+ return Ok(ty);
}
// See note in `rustc_trait_selection::traits::project` about why we
Reveal::UserFacing => ty.super_fold_with(self),
Reveal::All => {
- let substs = substs.super_fold_with(self);
+ let substs = substs.super_fold_with(self)?;
let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) {
let obligation = Obligation::with_depth(
// we don't need to replace them with placeholders (see branch below).
let tcx = self.infcx.tcx;
- let data = data.super_fold_with(self);
+ let data = data.super_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
- match tcx.normalize_projection_ty(c_data) {
- Ok(result) => {
- // We don't expect ambiguity.
- if result.is_ambiguous() {
- self.error = true;
- return ty.super_fold_with(self);
- }
-
- match self.infcx.instantiate_query_response_and_region_obligations(
- self.cause,
- self.param_env,
- &orig_values,
- result,
- ) {
- Ok(InferOk { value: result, obligations }) => {
- debug!("QueryNormalizer: result = {:#?}", result);
- debug!("QueryNormalizer: obligations = {:#?}", obligations);
- self.obligations.extend(obligations);
- result.normalized_ty
- }
-
- Err(_) => {
- self.error = true;
- ty.super_fold_with(self)
- }
- }
- }
-
- Err(NoSolution) => {
- self.error = true;
- ty.super_fold_with(self)
- }
+ let result = tcx.normalize_projection_ty(c_data)?;
+ // We don't expect ambiguity.
+ if result.is_ambiguous() {
+ return Err(NoSolution);
}
+ let InferOk { value: result, obligations } =
+ self.infcx.instantiate_query_response_and_region_obligations(
+ self.cause,
+ self.param_env,
+ &orig_values,
+ result,
+ )?;
+ debug!("QueryNormalizer: result = {:#?}", result);
+ debug!("QueryNormalizer: obligations = {:#?}", obligations);
+ self.obligations.extend(obligations);
+ Ok(result.normalized_ty)
}
ty::Projection(data) => {
&mut self.universes,
data,
);
- let data = data.super_fold_with(self);
+ let data = data.super_fold_with(self)?;
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
- match tcx.normalize_projection_ty(c_data) {
- Ok(result) => {
- // We don't expect ambiguity.
- if result.is_ambiguous() {
- self.error = true;
- return ty.super_fold_with(self);
- }
- match self.infcx.instantiate_query_response_and_region_obligations(
- self.cause,
- self.param_env,
- &orig_values,
- result,
- ) {
- Ok(InferOk { value: result, obligations }) => {
- debug!("QueryNormalizer: result = {:#?}", result);
- debug!("QueryNormalizer: obligations = {:#?}", obligations);
- self.obligations.extend(obligations);
- crate::traits::project::PlaceholderReplacer::replace_placeholders(
- infcx,
- mapped_regions,
- mapped_types,
- mapped_consts,
- &self.universes,
- result.normalized_ty,
- )
- }
- Err(_) => {
- self.error = true;
- ty.super_fold_with(self)
- }
- }
- }
- Err(NoSolution) => {
- self.error = true;
- ty.super_fold_with(self)
- }
+ let result = tcx.normalize_projection_ty(c_data)?;
+ // We don't expect ambiguity.
+ if result.is_ambiguous() {
+ return Err(NoSolution);
}
+ let InferOk { value: result, obligations } =
+ self.infcx.instantiate_query_response_and_region_obligations(
+ self.cause,
+ self.param_env,
+ &orig_values,
+ result,
+ )?;
+ debug!("QueryNormalizer: result = {:#?}", result);
+ debug!("QueryNormalizer: obligations = {:#?}", obligations);
+ self.obligations.extend(obligations);
+ Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ result.normalized_ty,
+ ))
}
_ => ty.super_fold_with(self),
- })();
+ })()?;
self.cache.insert(ty, res);
- res
+ Ok(res)
}
- fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- let constant = constant.super_fold_with(self);
- constant.eval(self.infcx.tcx, self.param_env)
+ fn fold_const(
+ &mut self,
+ constant: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ let constant = constant.super_fold_with(self)?;
+ Ok(constant.eval(self.infcx.tcx, self.param_env))
}
- fn fold_mir_const(&mut self, constant: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
+ fn fold_mir_const(
+ &mut self,
+ constant: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
constant.super_fold_with(self)
}
}
// This helps us avoid overflow: see issue #72839
// Since compilation is already guaranteed to fail, this is just
// to try to show the 'nicest' possible errors to the user.
- if obligation.references_error() {
+ // We don't check for errors in the `ParamEnv` - in practice,
+ // it seems to cause us to be overly aggressive in deciding
+ // to give up searching for candidates, leading to spurious errors.
+ if obligation.predicate.references_error() {
return;
}
.predicate
.to_poly_trait_ref()
.fold_with(&mut self.freshener)
+ .into_ok()
.with_constness(obligation.predicate.skip_binder().constness);
let dfn = previous_stack.cache.next_dfn();
predicates
.iter()
.map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars))
- .map(|wc| wc.fold_with(&mut regions_substitutor))
+ .map(|wc| wc.fold_with(&mut regions_substitutor).into_ok())
.filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect()
}
let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
let mut regions_substitutor =
lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
- let trait_ref = trait_ref.fold_with(&mut regions_substitutor);
+ let trait_ref = trait_ref.fold_with(&mut regions_substitutor).into_ok();
let where_clauses = self.where_clauses_for(def_id, bound_vars);
let self_ty = self_ty.subst(self.interner.tcx, bound_vars);
let mut regions_substitutor =
lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
- let self_ty = self_ty.fold_with(&mut regions_substitutor);
+ let self_ty = self_ty.fold_with(&mut regions_substitutor).into_ok();
let lowered_ty = self_ty.lower_into(&self.interner);
parameters[0].assert_ty_ref(&self.interner).could_match(
.iter()
.map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
.map(|bound| {
- bound.fold_with(&mut ty::fold::BottomUpFolder {
- tcx: self.interner.tcx,
- ty_op: |ty| {
- if let ty::Opaque(def_id, substs) = *ty.kind() {
- if def_id == opaque_ty_id.0 && substs == identity_substs {
- return self.interner.tcx.mk_ty(ty::Bound(
- ty::INNERMOST,
- ty::BoundTy::from(ty::BoundVar::from_u32(0)),
- ));
+ bound
+ .fold_with(&mut ty::fold::BottomUpFolder {
+ tcx: self.interner.tcx,
+ ty_op: |ty| {
+ if let ty::Opaque(def_id, substs) = *ty.kind() {
+ if def_id == opaque_ty_id.0 && substs == identity_substs {
+ return self.interner.tcx.mk_ty(ty::Bound(
+ ty::INNERMOST,
+ ty::BoundTy::from(ty::BoundVar::from_u32(0)),
+ ));
+ }
}
- }
- ty
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- })
+ ty
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ })
+ .into_ok()
})
.filter_map(|bound| {
LowerInto::<
.collect();
let mut bound_var_substitutor = NamedBoundVarSubstitutor::new(tcx, &named_parameters);
- let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor);
+ let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor).into_ok();
for var in named_parameters.values() {
parameters.insert(*var, chalk_ir::VariableKind::Lifetime);
self.tcx
}
- fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> {
+ fn fold_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: Binder<'tcx, T>,
+ ) -> Result<Binder<'tcx, T>, Self::Error> {
self.binder_index.shift_in(1);
let result = t.super_fold_with(self);
self.binder_index.shift_out(1);
result
}
- fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
+ fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
match r {
ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind {
ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) {
Some(idx) => {
let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) };
- return self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br));
+ return Ok(self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br)));
}
None => panic!("Missing `BrNamed`."),
},
self.tcx
}
- fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> {
+ fn fold_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: Binder<'tcx, T>,
+ ) -> Result<Binder<'tcx, T>, Self::Error> {
self.binder_index.shift_in(1);
let result = t.super_fold_with(self);
self.binder_index.shift_out(1);
result
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match *t.kind() {
// FIXME(chalk): currently we convert params to placeholders starting at
// index `0`. To support placeholders, we'll actually need to do a
// first pass to collect placeholders. Then we can insert params after.
ty::Placeholder(_) => unimplemented!(),
ty::Param(param) => match self.list.iter().position(|r| r == ¶m) {
- Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
+ Some(idx) => Ok(self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::from_usize(0),
name: ty::BoundVar::from_usize(idx),
- })),
+ }))),
None => {
self.list.push(param);
let idx = self.list.len() - 1 + self.next_ty_placeholder;
self.params.insert(idx, param);
- self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
+ Ok(self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
universe: ty::UniverseIndex::from_usize(0),
name: ty::BoundVar::from_usize(idx),
- }))
+ })))
}
},
}
}
- fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
+ fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
match r {
// FIXME(chalk) - jackh726 - this currently isn't hit in any tests.
// This covers any region variables in a goal, right?
var: ty::BoundVar::from_u32(*idx),
kind: ty::BrAnon(*idx),
};
- self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
+ Ok(self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)))
}
None => {
let idx = self.named_regions.len() as u32;
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) };
self.named_regions.insert(_re.def_id, idx);
- self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
+ Ok(self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)))
}
},
self.tcx
}
- fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
+ fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
match r {
ty::ReEmpty(ui) => {
assert_eq!(ui.as_usize(), 0);
- self.reempty_placeholder
+ Ok(self.reempty_placeholder)
}
_ => r.super_fold_with(self),
let mut params_substitutor =
ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder);
- let obligation = obligation.fold_with(&mut params_substitutor);
+ let obligation = obligation.fold_with(&mut params_substitutor).into_ok();
// FIXME(chalk): we really should be substituting these back in the solution
let _params: FxHashMap<usize, ParamTy> = params_substitutor.params;
let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder);
- let obligation = obligation.fold_with(&mut regions_substitutor);
+ let obligation = obligation.fold_with(&mut regions_substitutor).into_ok();
let max_universe = obligation.max_universe.index();
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
+#![feature(unwrap_infallible)]
#![recursion_limit = "256"]
#[macro_use]
normalize_mir_const_after_erasing_regions: |tcx, goal| {
normalize_after_erasing_regions(tcx, goal)
},
+ try_normalize_generic_arg_after_erasing_regions: |tcx, goal| {
+ debug!("try_normalize_generic_arg_after_erasing_regions(goal={:#?}", goal);
+
+ try_normalize_after_erasing_regions(tcx, goal)
+ },
+ try_normalize_mir_const_after_erasing_regions: |tcx, goal| {
+ try_normalize_after_erasing_regions(tcx, goal)
+ },
..*p
};
}
})
}
+#[instrument(level = "debug", skip(tcx))]
+fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Copy>(
+ tcx: TyCtxt<'tcx>,
+ goal: ParamEnvAnd<'tcx, T>,
+) -> Result<T, NoSolution> {
+ let ParamEnvAnd { param_env, value } = goal;
+ tcx.infer_ctxt().enter(|infcx| {
+ let cause = ObligationCause::dummy();
+ match infcx.at(&cause, param_env).normalize(value) {
+ Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
+ // We don't care about the `obligations`; they are
+ // always only region relations, and we are about to
+ // erase those anyway:
+ debug_assert_eq!(
+ normalized_obligations.iter().find(|p| not_outlives_predicate(&p.predicate)),
+ None,
+ );
+
+ let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
+ // It's unclear when `resolve_vars` would have an effect in a
+ // fresh `InferCtxt`. If this assert does trigger, it will give
+ // us a test case.
+ debug_assert_eq!(normalized_value, resolved_value);
+ let erased = infcx.tcx.erase_regions(resolved_value);
+ debug_assert!(!erased.needs_infer(), "{:?}", erased);
+ Ok(erased)
+ }
+ Err(NoSolution) => Err(NoSolution),
+ }
+ })
+}
+
fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool {
match p.kind().skip_binder() {
ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false,
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let parent_id = tcx.hir().get_parent_item(id);
let parent_def_id = tcx.hir().local_def_id(parent_id);
- let parent_item = tcx.hir().expect_item(parent_id);
+ let parent_item = tcx.hir().expect_item(parent_def_id);
match parent_item.kind {
hir::ItemKind::Impl(ref impl_) => {
if let Some(impl_item_ref) =
}
fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
if let hir::ItemKind::Impl(impl_) = &item.kind {
impl_.defaultness
} else {
}
fn impl_constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
if let hir::ItemKind::Impl(impl_) = &item.kind {
impl_.constness
} else {
}
fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
- let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
match item.kind {
hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
def_id: LocalDefId,
span: Span,
) {
- let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id));
+ let item = tcx.hir().expect_item(def_id);
debug!(?item, ?span);
struct FoundParentLifetime;
let ty = <dyn AstConv<'_>>::ast_ty_to_ty(fcx, ty);
// Get the `impl Trait`'s `DefId`.
if let ty::Opaque(def_id, _) = ty.kind() {
- let hir_id = fcx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
// Get the `impl Trait`'s `Item` so that we can get its trait bounds and
// get the `Trait`'s `DefId`.
if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }) =
- fcx.tcx.hir().expect_item(hir_id).kind
+ fcx.tcx.hir().expect_item(def_id.expect_local()).kind
{
// Are of this `impl Trait`'s traits object safe?
is_object_safe = bounds.iter().all(|bound| {
// First liberate late bound regions and subst placeholders
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id));
let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
- // Next, add all inputs and output as well-formed tys. Importantly,
- // we have to do this before normalization, since the normalized ty may
- // not contain the input parameters. See issue #87748.
- wf_tys.extend(trait_sig.inputs_and_output.iter());
let trait_sig =
inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig);
- // Also add the resulting inputs and output as well-formed.
- // This probably isn't strictly necessary.
+ // Add the resulting inputs and output as well-formed.
wf_tys.extend(trait_sig.inputs_and_output.iter());
let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
// When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
// span points only at the type `Box<Self`>, but we want to cover the whole
// argument pattern and type.
- let impl_m_hir_id =
- tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
ImplItemKind::Fn(ref sig, body) => tcx
.hir()
.body_param_names(body)
if trait_sig.inputs().len() == *i {
// Suggestion to change output type. We do not suggest in `async` functions
// to avoid complex logic or incorrect output.
- let impl_m_hir_id =
- tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
ImplItemKind::Fn(ref sig, _)
if sig.header.asyncness == hir::IsAsync::NotAsync =>
{
trait_m: &ty::AssocItem,
) -> (Span, Option<Span>) {
let tcx = infcx.tcx;
- let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let mut impl_args = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ let mut impl_args = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
ImplItemKind::Fn(ref sig, _) => {
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
}
_ => bug!("{:?} is not a method", impl_m),
};
- let trait_args = trait_m.def_id.as_local().map(|def_id| {
- let trait_m_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- match tcx.hir().expect_trait_item(trait_m_hir_id).kind {
+ let trait_args =
+ trait_m.def_id.as_local().map(|def_id| match tcx.hir().expect_trait_item(def_id).kind {
TraitItemKind::Fn(ref sig, _) => {
sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span()))
}
_ => bug!("{:?} is not a TraitItemKind::Fn", trait_m),
- }
- });
+ });
match *terr {
TypeError::ArgumentMutability(i) => {
err_occurred = true;
let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
- let trait_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let trait_item = tcx.hir().expect_trait_item(trait_hir_id);
+ let trait_item = tcx.hir().expect_trait_item(def_id);
if trait_item.generics.params.is_empty() {
(Some(vec![trait_item.generics.span]), vec![])
} else {
(trait_span.map(|s| vec![s]), vec![])
};
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_.def_id.expect_local());
- let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
+ let impl_item = tcx.hir().expect_impl_item(impl_.def_id.expect_local());
let impl_item_impl_trait_spans: Vec<Span> = impl_item
.generics
.params
let impl_number_args = impl_m_fty.inputs().skip_binder().len();
if trait_number_args != impl_number_args {
let trait_span = if let Some(def_id) = trait_m.def_id.as_local() {
- let trait_id = tcx.hir().local_def_id_to_hir_id(def_id);
- match tcx.hir().expect_trait_item(trait_id).kind {
+ match tcx.hir().expect_trait_item(def_id).kind {
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) {
} else {
trait_item_span
};
- let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
- let impl_span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
+ let impl_span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
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) {
);
// Locate the Span containing just the type of the offending impl
- match tcx.hir().expect_impl_item(impl_c_hir_id).kind {
+ match tcx.hir().expect_impl_item(impl_c.def_id.expect_local()).kind {
ImplItemKind::Const(ref ty, _) => cause.make_mut().span = ty.span,
_ => bug!("{:?} is not a impl const", impl_c),
}
trait_c.ident
);
- let trait_c_hir_id =
- trait_c.def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
- let trait_c_span = trait_c_hir_id.map(|trait_c_hir_id| {
+ let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
// Add a label to the Span containing just the type of the const
- match tcx.hir().expect_trait_item(trait_c_hir_id).kind {
+ match tcx.hir().expect_trait_item(trait_c_def_id).kind {
TraitItemKind::Const(ref ty, _) => ty.span,
_ => bug!("{:?} is not a trait const", trait_c),
}
(_, _) => return None,
};
- let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_local_id);
- let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_local_id);
-
match (
- &self.tcx.hir().expect_item(last_hir_id).kind,
- &self.tcx.hir().expect_item(exp_hir_id).kind,
+ &self.tcx.hir().expect_item(last_local_id).kind,
+ &self.tcx.hir().expect_item(exp_local_id).kind,
) {
(
hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }),
let import_items: Vec<_> = applicable_trait
.import_ids
.iter()
- .map(|&import_id| {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(import_id);
- self.tcx.hir().expect_item(hir_id)
- })
+ .map(|&import_id| self.tcx.hir().expect_item(import_id))
.collect();
// Find an identifier with which this trait was imported (note that `_` doesn't count).
let mut wf_tys = FxHashSet::default();
// Compute the fty from point of view of inside the fn.
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
- wf_tys.extend(fn_sig.inputs_and_output.iter());
let fn_sig = inh.normalize_associated_types_in(
body.value.span,
body_id.hir_id,
let mut eraser = TypeParamEraser(self, expr.span);
let needs_bound = self
.lookup_op_method(
- eraser.fold_ty(lhs_ty),
- &[eraser.fold_ty(rhs_ty)],
+ eraser.fold_ty(lhs_ty).into_ok(),
+ &[eraser.fold_ty(rhs_ty).into_ok()],
Op::Binary(op, is_assign),
)
.is_ok();
self.0.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match ty.kind() {
- ty::Param(_) => self.0.next_ty_var(TypeVariableOrigin {
+ ty::Param(_) => Ok(self.0.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::MiscVariable,
span: self.1,
- }),
+ })),
_ => ty.super_fold_with(self),
}
}
/// the types first.
#[instrument(skip(tcx), level = "debug")]
pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id);
debug!(
?item.def_id,
pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let trait_item = tcx.hir().expect_trait_item(hir_id);
+ let trait_item = tcx.hir().expect_trait_item(def_id);
let (method_sig, span) = match trait_item.kind {
hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
check_object_unsafe_self_trait_by_name(tcx, trait_item);
check_associated_item(tcx, trait_item.def_id, span, method_sig);
- let encl_trait_hir_id = tcx.hir().get_parent_item(hir_id);
- let encl_trait = tcx.hir().expect_item(encl_trait_hir_id);
+ let encl_trait_def_id = tcx.hir().get_parent_did(hir_id);
+ let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
let encl_trait_def_id = encl_trait.def_id.to_def_id();
let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
Some("fn")
}
pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let impl_item = tcx.hir().expect_impl_item(hir_id);
+ let impl_item = tcx.hir().expect_impl_item(def_id);
let (method_sig, span) = match impl_item.kind {
hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
);
}
+ // Ensure that the end result is `Sync` in a non-thread local `static`.
+ let should_check_for_sync = tcx.static_mutability(item_id.to_def_id())
+ == Some(hir::Mutability::Not)
+ && !tcx.is_foreign_item(item_id.to_def_id())
+ && !tcx.is_thread_local_static(item_id.to_def_id());
+
+ if should_check_for_sync {
+ fcx.register_bound(
+ item_ty,
+ tcx.require_lang_item(LangItem::Sync, Some(ty_span)),
+ traits::ObligationCause::new(ty_span, fcx.body_id, traits::SharedStatic),
+ );
+ }
+
// No implied bounds in a const, etc.
FxHashSet::default()
});
) {
let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig);
- // Unnormalized types in signature are WF too
- implied_bounds.extend(sig.inputs());
- // FIXME(#27579) return types should not be implied bounds
- implied_bounds.insert(sig.output());
-
// Normalize the input and output types one at a time, using a different
// `WellFormedLoc` for each. We cannot call `normalize_associated_types`
// on the entire `FnSig`, since this would use the same `WellFormedLoc`
T: TypeFoldable<'tcx>,
{
let mut resolver = Resolver::new(self.fcx, span, self.body);
- let x = x.fold_with(&mut resolver);
+ let x = x.fold_with(&mut resolver).into_ok();
if cfg!(debug_assertions) && x.needs_infer() {
span_bug!(span.to_span(self.fcx.tcx), "writeback: `{:?}` has inference variables", x);
}
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if ty.has_type_flags(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
ty.super_fold_with(self)
} else {
- ty
+ Ok(ty)
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased }
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ Ok(if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased })
}
}
self.tcx
}
- fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
match self.infcx.fully_resolve(t) {
Ok(t) => {
// Do not anonymize late-bound regions
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
self.report_type_error(t);
self.replaced_with_error = true;
- self.tcx().ty_error()
+ Ok(self.tcx().ty_error())
}
}
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
debug_assert!(!r.is_late_bound(), "Should not be resolving bound region.");
- self.tcx.lifetimes.re_erased
+ Ok(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) {
+ fn fold_const(
+ &mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+ Ok(match self.infcx.fully_resolve(ct) {
Ok(ct) => self.infcx.tcx.erase_regions(ct),
Err(_) => {
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
self.replaced_with_error = true;
self.tcx().const_error(ct.ty)
}
- }
+ })
}
}
for extern_crate in &crates_to_lint {
let def_id = extern_crate.def_id.expect_local();
- let id = tcx.hir().local_def_id_to_hir_id(def_id);
- let item = tcx.hir().expect_item(id);
+ let item = tcx.hir().expect_item(def_id);
// If the crate is fully unused, we suggest removing it altogether.
// We do this in any edition.
if extern_crate.warn_if_unused {
if let Some(&span) = unused_extern_crates.get(&def_id) {
+ let id = tcx.hir().local_def_id_to_hir_id(def_id);
tcx.struct_span_lint_hir(lint, id, span, |lint| {
// Removal suggestion span needs to include attributes (Issue #54400)
let span_with_attrs = tcx
if !tcx.get_attrs(extern_crate.def_id).is_empty() {
continue;
}
+ let id = tcx.hir().local_def_id_to_hir_id(def_id);
tcx.struct_span_lint_hir(lint, id, extern_crate.span, |lint| {
// Otherwise, we can convert it into a `use` of some kind.
let base_replacement = match extern_crate.orig_name {
return;
}
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
- let sp = match tcx.hir().expect_item(impl_hir_id).kind {
+ let sp = match tcx.hir().expect_item(impl_did).kind {
ItemKind::Impl(ref impl_) => impl_.self_ty.span,
_ => bug!("expected Drop impl item"),
};
match can_type_implement_copy(tcx, param_env, self_type) {
Ok(()) => {}
Err(CopyImplementationError::InfrigingFields(fields)) => {
- let item = tcx.hir().expect_item(impl_hir_id);
+ let item = tcx.hir().expect_item(impl_did);
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref tr), .. }) = item.kind {
tr.path.span
} else {
err.emit()
}
Err(CopyImplementationError::NotAnAdt) => {
- let item = tcx.hir().expect_item(impl_hir_id);
+ let item = tcx.hir().expect_item(impl_did);
let span =
if let ItemKind::Impl(ref impl_) = item.kind { impl_.self_ty.span } else { span };
debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
// this provider should only get invoked for local def-ids
- let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did.expect_local());
- let span = tcx.hir().span(impl_hir_id);
+ let impl_did = impl_did.expect_local();
+ let span = tcx.def_span(impl_did);
let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
tcx.infer_ctxt().enter(|infcx| {
+ let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
let cause = ObligationCause::misc(span, impl_hir_id);
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
mt_b: ty::TypeAndMut<'tcx>,
.emit();
return err_info;
} else if diff_fields.len() > 1 {
- let item = tcx.hir().expect_item(impl_hir_id);
+ let item = tcx.hir().expect_item(impl_did);
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) =
item.kind
{
t.path.span
} else {
- tcx.hir().span(impl_hir_id)
+ tcx.def_span(impl_did)
};
struct_span_err!(
// Finally, resolve all regions.
let outlives_env = OutlivesEnvironment::new(param_env);
- infcx.resolve_regions_and_report_errors(impl_did, &outlives_env, RegionckMode::default());
+ infcx.resolve_regions_and_report_errors(
+ impl_did.to_def_id(),
+ &outlives_env,
+ RegionckMode::default(),
+ );
CoerceUnsizedInfo { custom_kind: kind }
})
match self.node() {
hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
let item =
- self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(self.hir_id()));
+ self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(self.hir_id()));
match &item.kind {
hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Struct(_, generics)
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
None => true,
})
- .flat_map(|b| predicates_from_bound(self, ty, b));
+ .flat_map(|b| predicates_from_bound(self, ty, b, ty::List::empty()));
let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
let from_where_clauses = ast_generics
} else {
None
};
+ let bvars = self.tcx.late_bound_vars(bp.bounded_ty.hir_id);
+
bp.bounds
.iter()
.filter(|b| match assoc_name {
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
None => true,
})
- .filter_map(move |b| bt.map(|bt| (bt, b)))
+ .filter_map(move |b| bt.map(|bt| (bt, b, bvars)))
})
- .flat_map(|(bt, b)| predicates_from_bound(self, bt, b));
+ .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars));
from_ty_params.chain(from_where_clauses).collect()
}
}
fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
let (is_auto, unsafety) = match item.kind {
hir::ItemKind::Trait(is_auto, unsafety, ..) => (is_auto == hir::IsAuto::Yes, unsafety),
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
let icx = ItemCtxt::new(tcx, def_id);
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- match tcx.hir().expect_item(hir_id).kind {
+ match tcx.hir().expect_item(def_id.expect_local()).kind {
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id);
<dyn AstConv<'_>>::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
}
fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
- let item = tcx.hir().expect_item(hir_id);
+ let item = tcx.hir().expect_item(def_id.expect_local());
match &item.kind {
hir::ItemKind::Impl(hir::Impl {
polarity: hir::ImplPolarity::Negative(span),
astconv: &dyn AstConv<'tcx>,
param_ty: Ty<'tcx>,
bound: &'tcx hir::GenericBound<'tcx>,
+ bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let mut bounds = Bounds::default();
- astconv.add_bounds(
- param_ty,
- std::array::IntoIter::new([bound]),
- &mut bounds,
- ty::List::empty(),
- );
+ astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
bounds.predicates(astconv.tcx(), param_ty)
}
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
let node = tcx.hir().get(hir_id);
if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
- let parent_id = tcx.hir().get_parent_item(hir_id);
+ let parent_id = tcx.hir().get_parent_did(hir_id);
let parent_item = tcx.hir().expect_item(parent_id);
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
tcx.sess
self.tcx
}
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !self.success {
- return ty;
+ return Ok(ty);
}
match ty.kind() {
- ty::FnDef(def_id, _) => self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id)),
+ ty::FnDef(def_id, _) => Ok(self.tcx.mk_fn_ptr(self.tcx.fn_sig(*def_id))),
// FIXME: non-capturing closures should also suggest a function pointer
ty::Closure(..) | ty::Generator(..) => {
self.success = false;
- ty
+ Ok(ty)
}
_ => ty.super_fold_with(self),
}
// Suggesting unnameable types won't help.
let mut mk_nameable = MakeNameable::new(tcx);
- let ty = mk_nameable.fold_ty(ty);
+ let ty = mk_nameable.fold_ty(ty).into_ok();
let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
if let Some(sugg_ty) = sugg_ty {
err.span_suggestion(
if !ty.references_error() {
let mut mk_nameable = MakeNameable::new(tcx);
- let ty = mk_nameable.fold_ty(ty);
+ let ty = mk_nameable.fold_ty(ty).into_ok();
let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
if let Some(sugg_ty) = sugg_ty {
diag.span_suggestion(
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
self.tcx.infer_ctxt().enter(|infcx| {
let mut fulfill = traits::FulfillmentContext::new();
- let tcx_ty =
- self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
+ let tcx_ty = self
+ .icx
+ .to_ty(ty)
+ .fold_with(&mut EraseAllBoundRegions { tcx: self.tcx })
+ .into_ok();
let cause = traits::ObligationCause::new(
ty.span,
self.hir_id,
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
self.tcx
}
- fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
- if let ty::ReLateBound(..) = r { &ty::ReErased } else { r }
+ fn fold_region(&mut self, r: Region<'tcx>) -> Result<Region<'tcx>, Self::Error> {
+ if let ty::ReLateBound(..) = r { Ok(&ty::ReErased) } else { Ok(r) }
}
}
#![feature(slice_partition_dedup)]
#![feature(control_flow_enum)]
#![feature(hash_drain_filter)]
+#![feature(unwrap_infallible)]
#![recursion_limit = "256"]
#[macro_use]
}
}
+ /// A specialized version of `reserve()` used only by the hot and
+ /// oft-instantiated `Vec::push()`, which does its own capacity check.
+ #[cfg(not(no_global_oom_handling))]
+ #[inline(never)]
+ pub fn reserve_for_push(&mut self, len: usize) {
+ handle_reserve(self.grow_amortized(len, 1));
+ }
+
/// The same as `reserve`, but returns on errors instead of panicking or aborting.
pub fn try_reserve(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
if self.needs_to_grow(len, additional) {
assert!(v.capacity() >= 12 + 12 / 2);
}
}
+
+struct ZST;
+
+// A `RawVec` holding zero-sized elements should always look like this.
+fn zst_sanity<T>(v: &RawVec<T>) {
+ assert_eq!(v.capacity(), usize::MAX);
+ assert_eq!(v.ptr(), core::ptr::Unique::<T>::dangling().as_ptr());
+ assert_eq!(v.current_memory(), None);
+}
+
+#[test]
+fn zst() {
+ let cap_err = Err(crate::collections::TryReserveErrorKind::CapacityOverflow.into());
+
+ assert_eq!(std::mem::size_of::<ZST>(), 0);
+
+ // All these different ways of creating the RawVec produce the same thing.
+
+ let v: RawVec<ZST> = RawVec::new();
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::with_capacity_in(100, Global);
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::allocate_in(0, AllocInit::Uninitialized, Global);
+ zst_sanity(&v);
+
+ let v: RawVec<ZST> = RawVec::allocate_in(100, AllocInit::Uninitialized, Global);
+ zst_sanity(&v);
+
+ let mut v: RawVec<ZST> = RawVec::allocate_in(usize::MAX, AllocInit::Uninitialized, Global);
+ zst_sanity(&v);
+
+ // Check all these operations work as expected with zero-sized elements.
+
+ assert!(!v.needs_to_grow(100, usize::MAX - 100));
+ assert!(v.needs_to_grow(101, usize::MAX - 100));
+ zst_sanity(&v);
+
+ v.reserve(100, usize::MAX - 100);
+ //v.reserve(101, usize::MAX - 100); // panics, in `zst_reserve_panic` below
+ zst_sanity(&v);
+
+ v.reserve_exact(100, usize::MAX - 100);
+ //v.reserve_exact(101, usize::MAX - 100); // panics, in `zst_reserve_exact_panic` below
+ zst_sanity(&v);
+
+ assert_eq!(v.try_reserve(100, usize::MAX - 100), Ok(()));
+ assert_eq!(v.try_reserve(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+
+ assert_eq!(v.try_reserve_exact(100, usize::MAX - 100), Ok(()));
+ assert_eq!(v.try_reserve_exact(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+
+ assert_eq!(v.grow_amortized(100, usize::MAX - 100), cap_err);
+ assert_eq!(v.grow_amortized(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+
+ assert_eq!(v.grow_exact(100, usize::MAX - 100), cap_err);
+ assert_eq!(v.grow_exact(101, usize::MAX - 100), cap_err);
+ zst_sanity(&v);
+}
+
+#[test]
+#[should_panic(expected = "capacity overflow")]
+fn zst_reserve_panic() {
+ let mut v: RawVec<ZST> = RawVec::new();
+ zst_sanity(&v);
+
+ v.reserve(101, usize::MAX - 100);
+}
+
+#[test]
+#[should_panic(expected = "capacity overflow")]
+fn zst_reserve_exact_panic() {
+ let mut v: RawVec<ZST> = RawVec::new();
+ zst_sanity(&v);
+
+ v.reserve_exact(101, usize::MAX - 100);
+}
pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
let mut iter = lossy::Utf8Lossy::from_bytes(v).chunks();
- let (first_valid, first_broken) = if let Some(chunk) = iter.next() {
+ let first_valid = if let Some(chunk) = iter.next() {
let lossy::Utf8LossyChunk { valid, broken } = chunk;
- if valid.len() == v.len() {
- debug_assert!(broken.is_empty());
+ if broken.is_empty() {
+ debug_assert_eq!(valid.len(), v.len());
return Cow::Borrowed(valid);
}
- (valid, broken)
+ valid
} else {
return Cow::Borrowed("");
};
let mut res = String::with_capacity(v.len());
res.push_str(first_valid);
- if !first_broken.is_empty() {
- res.push_str(REPLACEMENT);
- }
+ res.push_str(REPLACEMENT);
for lossy::Utf8LossyChunk { valid, broken } in iter {
res.push_str(valid);
// This will panic or abort if we would allocate > isize::MAX bytes
// or if the length increment would overflow for zero-sized types.
if self.len == self.buf.capacity() {
- self.reserve(1);
+ self.buf.reserve_for_push(self.len);
}
unsafe {
let end = self.as_mut_ptr().add(self.len);
assert_eq!(i.advance_by(usize::MAX), Err(0));
+ i.advance_by(0).unwrap();
+ i.advance_back_by(0).unwrap();
+
assert_eq!(i.len(), 0);
}
// > `usize::MAX`)
let new_size = self.size() + pad;
- Layout::from_size_align(new_size, self.align()).unwrap()
+ // SAFETY: self.align is already known to be valid and new_size has been
+ // padded already.
+ unsafe { Layout::from_size_align_unchecked(new_size, self.align()) }
}
/// Creates a layout describing the record for `n` instances of
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
#[inline]
pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
- let (layout, offset) = Layout::new::<T>().repeat(n)?;
- debug_assert_eq!(offset, mem::size_of::<T>());
- Ok(layout.pad_to_align())
+ let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?;
+
+ // SAFETY:
+ // - Size: `array_size` cannot be too big because `size_of::<T>()` must
+ // be a multiple of `align_of::<T>()`. Therefore, `array_size`
+ // rounded up to the nearest multiple of `align_of::<T>()` is just
+ // `array_size`. And `array_size` cannot be too big because it was
+ // just checked by the `checked_mul()`.
+ // - Alignment: `align_of::<T>()` will always give an acceptable
+ // (non-zero, power of two) alignment.
+ Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) })
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Pointer for *const T {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
- let old_width = f.width;
- let old_flags = f.flags;
-
- // The alternate flag is already treated by LowerHex as being special-
- // it denotes whether to prefix with 0x. We use it to work out whether
- // or not to zero extend, and then unconditionally set it to get the
- // prefix.
- if f.alternate() {
- f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
-
- if f.width.is_none() {
- f.width = Some((usize::BITS / 4) as usize + 2);
+ /// Since the formatting will be identical for all pointer types, use a non-monomorphized
+ /// implementation for the actual formatting to reduce the amount of codegen work needed
+ fn inner(ptr: *const (), f: &mut Formatter<'_>) -> Result {
+ let old_width = f.width;
+ let old_flags = f.flags;
+
+ // The alternate flag is already treated by LowerHex as being special-
+ // it denotes whether to prefix with 0x. We use it to work out whether
+ // or not to zero extend, and then unconditionally set it to get the
+ // prefix.
+ if f.alternate() {
+ f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
+
+ if f.width.is_none() {
+ f.width = Some((usize::BITS / 4) as usize + 2);
+ }
}
- }
- f.flags |= 1 << (FlagV1::Alternate as u32);
+ f.flags |= 1 << (FlagV1::Alternate as u32);
+
+ let ret = LowerHex::fmt(&(ptr as usize), f);
- let ret = LowerHex::fmt(&(*self as *const () as usize), f);
+ f.width = old_width;
+ f.flags = old_flags;
- f.width = old_width;
- f.flags = old_flags;
+ ret
+ }
- ret
+ inner(*self as *const (), f)
}
}
/// `0xFF` byte to the `Hasher` so that the values `("ab", "c")` and `("a",
/// "bc")` hash differently.
///
+/// ## Portability
+///
+/// Due to differences in endianness and type sizes, data fed by `Hash` to a `Hasher`
+/// should not be considered portable across platforms. Additionally the data passed by most
+/// standard library types should not be considered stable between compiler versions.
+///
+/// This means tests shouldn't probe hard-coded hash values or data fed to a `Hasher` and
+/// instead should check consistency with `Eq`.
+///
+/// Serialization formats intended to be portable between platforms or compiler versions should
+/// either avoid encoding hashes or only rely on `Hash` and `Hasher` implementations that
+/// provide additional guarantees.
+///
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
/// [`HashSet`]: ../../std/collections/struct.HashSet.html
/// [`hash`]: Hash::hash
/// This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
- #[rustc_const_unstable(feature = "const_assert_type", issue = "none")]
+ #[rustc_const_stable(feature = "const_assert_type", since = "1.59.0")]
pub fn assert_inhabited<T>();
/// A guard for unsafe functions that cannot ever be executed if `T` does not permit
/// zero-initialization: This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
+ #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
pub fn assert_zero_valid<T>();
/// A guard for unsafe functions that cannot ever be executed if `T` has invalid
/// bit patterns: This will statically either panic, or do nothing.
///
/// This intrinsic does not have a stable counterpart.
+ #[rustc_const_unstable(feature = "const_assert_type2", issue = "none")]
pub fn assert_uninit_valid<T>();
/// Gets a reference to a static `Location` indicating where it was called.
#[rustc_inherit_overflow_checks]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
let mut rem = n;
-
let step_one = self.n.saturating_add(rem);
+
match self.iter.advance_by(step_one) {
Ok(_) => {
rem -= step_one - self.n;
Err(advanced) => {
let advanced_without_skip = advanced.saturating_sub(self.n);
self.n = self.n.saturating_sub(advanced);
- return Err(advanced_without_skip);
+ return if n == 0 { Ok(()) } else { Err(advanced_without_skip) };
}
}
}
#[inline]
+ #[rustc_inherit_overflow_checks]
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
- let inner_len = self.iter.len();
- let len = self.n;
- let remainder = len.saturating_sub(n);
- let to_advance = inner_len - remainder;
- match self.iter.advance_back_by(to_advance) {
- Ok(_) => {
- self.n = remainder;
- if n > len {
- return Err(len);
- }
- return Ok(());
- }
- _ => panic!("ExactSizeIterator contract violation"),
- }
+ // The amount by which the inner iterator needs to be shortened for it to be
+ // at most as long as the take() amount.
+ let trim_inner = self.iter.len().saturating_sub(self.n);
+ // The amount we need to advance inner to fulfill the caller's request.
+ // take(), advance_by() and len() all can be at most usize, so we don't have to worry
+ // about having to advance more than usize::MAX here.
+ let advance_by = trim_inner.saturating_add(n);
+
+ let advanced = match self.iter.advance_back_by(advance_by) {
+ Ok(_) => advance_by - trim_inner,
+ Err(advanced) => advanced - trim_inner,
+ };
+ self.n -= advanced;
+ return if advanced < n { Err(advanced) } else { Ok(()) };
}
}
/// Calling `advance_back_by(0)` can do meaningful work, for example [`Flatten`] can advance its
/// outer iterator until it finds an inner iterator that is not empty, which then often
/// allows it to return a more accurate `size_hint()` than in its initial state.
- /// `advance_back_by(0)` may either return `Ok()` or `Err(0)`. The former conveys no information
- /// whether the iterator is or is not exhausted, the latter can be treated as if [`next_back`]
- /// had returned `None`. Replacing a `Err(0)` with `Ok` is only correct for `n = 0`.
///
/// [`advance_by`]: Iterator::advance_by
/// [`Flatten`]: crate::iter::Flatten
/// Calling `advance_by(0)` can do meaningful work, for example [`Flatten`]
/// can advance its outer iterator until it finds an inner iterator that is not empty, which
/// then often allows it to return a more accurate `size_hint()` than in its initial state.
- /// `advance_by(0)` may either return `Ok()` or `Err(0)`. The former conveys no information
- /// whether the iterator is or is not exhausted, the latter can be treated as if [`next`]
- /// had returned `None`. Replacing a `Err(0)` with `Ok` is only correct for `n = 0`.
///
/// [`Flatten`]: crate::iter::Flatten
/// [`next`]: Iterator::next
/// In other words, it zips two iterators together, into a single one.
///
/// If either iterator returns [`None`], [`next`] from the zipped iterator
- /// will return [`None`]. If the first iterator returns [`None`], `zip` will
- /// short-circuit and `next` will not be called on the second iterator.
+ /// will return [`None`].
+ /// If the zipped iterator has no more elements to return then each further attempt to advance
+ /// it will first try to advance the first iterator at most one time and if it still yielded an item
+ /// try to advance the second iterator at most one time.
///
/// # Examples
///
/// assert_eq!(iter.next(), None);
/// ```
#[inline]
+ #[doc(alias = "drop_while")]
#[stable(feature = "rust1", since = "1.0.0")]
fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
where
#![feature(const_align_of_val)]
#![feature(const_alloc_layout)]
#![feature(const_arguments_as_str)]
-#![feature(const_assert_type)]
#![feature(const_bigint_helper_methods)]
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_intrinsic_copy)]
#![feature(const_intrinsic_forget)]
#![feature(const_likely)]
-#![feature(const_maybe_uninit_as_ptr)]
+#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(const_num_from_num)]
#![feature(const_ops)]
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
/// until they are, it is advisable to avoid them.)
#[stable(feature = "maybe_uninit", since = "1.36.0")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_as_ptr", issue = "75251")]
+ #[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")]
#[inline(always)]
pub const fn as_ptr(&self) -> *const T {
// `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
/// until they are, it is advisable to avoid them.)
#[stable(feature = "maybe_uninit", since = "1.36.0")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_as_ptr", issue = "75251")]
+ #[rustc_const_unstable(feature = "const_maybe_uninit_as_mut_ptr", issue = "75251")]
#[inline(always)]
pub const fn as_mut_ptr(&mut self) -> *mut T {
// `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
/// // `x` had not been initialized yet, so this last line caused undefined behavior. ⚠️
/// ```
#[stable(feature = "maybe_uninit", since = "1.36.0")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
+ #[rustc_const_stable(feature = "const_maybe_uninit_assume_init", since = "1.59.0")]
#[inline(always)]
#[rustc_diagnostic_item = "assume_init"]
#[track_caller]
/// }
/// ```
#[stable(feature = "maybe_uninit_ref", since = "1.55.0")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
+ #[rustc_const_stable(feature = "const_maybe_uninit_assume_init", since = "1.59.0")]
+ #[cfg_attr(bootstrap, rustc_allow_const_fn_unstable(const_raw_ptr_deref))]
#[inline(always)]
pub const unsafe fn assume_init_ref(&self) -> &T {
// SAFETY: the caller must guarantee that `self` is initialized.
///
/// [`assume_init_ref`]: MaybeUninit::assume_init_ref
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
- #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init", issue = "none")]
+ #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[inline(always)]
pub const unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] {
// SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that
/// Basic usage:
///
/// ```
- /// #![feature(nonzero_is_power_of_two)]
- ///
#[doc = concat!("let eight = std::num::", stringify!($Ty), "::new(8).unwrap();")]
/// assert!(eight.is_power_of_two());
#[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")]
/// assert!(!ten.is_power_of_two());
/// ```
#[must_use]
- #[unstable(feature = "nonzero_is_power_of_two", issue = "81106")]
+ #[stable(feature = "nonzero_is_power_of_two", since = "1.59.0")]
#[inline]
pub const fn is_power_of_two(self) -> bool {
// LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here.
}
}
+ /// Calls the provided closure with a reference to the contained value (if [`Some`]).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(result_option_inspect)]
+ ///
+ /// let v = vec![1, 2, 3, 4, 5];
+ ///
+ /// // prints "got: 4"
+ /// let x: Option<&usize> = v.get(3).inspect(|x| println!("got: {}", x));
+ ///
+ /// // prints nothing
+ /// let x: Option<&usize> = v.get(5).inspect(|x| println!("got: {}", x));
+ /// ```
+ #[inline]
+ #[unstable(feature = "result_option_inspect", issue = "91345")]
+ pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
+ if let Some(ref x) = self {
+ f(x);
+ }
+
+ self
+ }
+
/// Returns the provided default result (if none),
/// or applies a function to the contained value (if any).
///
}
}
+ /// Calls the provided closure with a reference to the contained value (if [`Ok`]).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(result_option_inspect)]
+ ///
+ /// let x: u8 = "4"
+ /// .parse::<u8>()
+ /// .inspect(|x| println!("original: {}", x))
+ /// .map(|x| x.pow(3))
+ /// .expect("failed to parse number");
+ /// ```
+ #[inline]
+ #[unstable(feature = "result_option_inspect", issue = "91345")]
+ pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self {
+ if let Ok(ref t) = self {
+ f(t);
+ }
+
+ self
+ }
+
+ /// Calls the provided closure with a reference to the contained error (if [`Err`]).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(result_option_inspect)]
+ ///
+ /// use std::{fs, io};
+ ///
+ /// fn read() -> io::Result<String> {
+ /// fs::read_to_string("address.txt")
+ /// .inspect_err(|e| eprintln!("failed to read file: {}", e))
+ /// }
+ /// ```
+ #[inline]
+ #[unstable(feature = "result_option_inspect", issue = "91345")]
+ pub fn inspect_err<F: FnOnce(&E)>(self, f: F) -> Self {
+ if let Err(ref e) = self {
+ f(e);
+ }
+
+ self
+ }
+
/////////////////////////////////////////////////////////////////////////
// Iterator constructors
/////////////////////////////////////////////////////////////////////////
}
let mut i = 0;
+ let mut valid_up_to = 0;
while i < self.source.len() {
- let i_ = i;
-
- // SAFETY: `i` starts at `0`, is less than `self.source.len()`, and
- // only increases, so `0 <= i < self.source.len()`.
+ // SAFETY: `i < self.source.len()` per previous line.
+ // For some reason the following are both significantly slower:
+ // while let Some(&byte) = self.source.get(i) {
+ // while let Some(byte) = self.source.get(i).copied() {
let byte = unsafe { *self.source.get_unchecked(i) };
i += 1;
if byte < 128 {
+ // This could be a `1 => ...` case in the match below, but for
+ // the common case of all-ASCII inputs, we bypass loading the
+ // sizeable UTF8_CHAR_WIDTH table into cache.
} else {
let w = utf8_char_width(byte);
- macro_rules! error {
- () => {{
- // SAFETY: We have checked up to `i` that source is valid UTF-8.
- unsafe {
- let r = Utf8LossyChunk {
- valid: from_utf8_unchecked(&self.source[0..i_]),
- broken: &self.source[i_..i],
- };
- self.source = &self.source[i..];
- return Some(r);
- }
- }};
- }
-
match w {
2 => {
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
}
(0xE1..=0xEC, 0x80..=0xBF) => (),
(0xED, 0x80..=0x9F) => (),
(0xEE..=0xEF, 0x80..=0xBF) => (),
- _ => {
- error!();
- }
+ _ => break,
}
i += 1;
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
}
(0xF0, 0x90..=0xBF) => (),
(0xF1..=0xF3, 0x80..=0xBF) => (),
(0xF4, 0x80..=0x8F) => (),
- _ => {
- error!();
- }
+ _ => break,
}
i += 1;
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
if safe_get(self.source, i) & 192 != TAG_CONT_U8 {
- error!();
+ break;
}
i += 1;
}
- _ => {
- error!();
- }
+ _ => break,
}
}
+
+ valid_up_to = i;
}
- let r = Utf8LossyChunk {
- // SAFETY: We have checked that the entire source is valid UTF-8.
- valid: unsafe { from_utf8_unchecked(self.source) },
- broken: &[],
- };
- self.source = &[];
- Some(r)
+ // SAFETY: `i <= self.source.len()` because it is only ever incremented
+ // via `i += 1` and in between every single one of those increments, `i`
+ // is compared against `self.source.len()`. That happens either
+ // literally by `i < self.source.len()` in the while-loop's condition,
+ // or indirectly by `safe_get(self.source, i) & 192 != TAG_CONT_U8`. The
+ // loop is terminated as soon as the latest `i += 1` has made `i` no
+ // longer less than `self.source.len()`, which means it'll be at most
+ // equal to `self.source.len()`.
+ let (inspected, remaining) = unsafe { self.source.split_at_unchecked(i) };
+ self.source = remaining;
+
+ // SAFETY: `valid_up_to <= i` because it is only ever assigned via
+ // `valid_up_to = i` and `i` only increases.
+ let (valid, broken) = unsafe { inspected.split_at_unchecked(valid_up_to) };
+
+ Some(Utf8LossyChunk {
+ // SAFETY: All bytes up to `valid_up_to` are valid UTF-8.
+ valid: unsafe { from_utf8_unchecked(valid) },
+ broken,
+ })
}
}
// https://tools.ietf.org/html/rfc3629
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,
- 1, // 0x3F
- 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, // 0x5F
- 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, // 0x7F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, // 0x9F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, // 0xBF
- 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, // 0xDF
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF
- 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF
+ // 1 2 3 4 5 6 7 8 9 A B C D E F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
+ 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, 1, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // D
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // E
+ 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F
];
/// Given a first byte, determines how many bytes are in this UTF-8 character.
iter.advance_by(i).unwrap();
assert_eq!(iter.next(), Some(&xs[i]));
assert_eq!(iter.advance_by(100), Err(len - i - 1));
+ iter.advance_by(0).unwrap();
}
for i in 0..ys.len() {
iter.advance_by(xs.len() + i).unwrap();
assert_eq!(iter.next(), Some(&ys[i]));
assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1));
+ iter.advance_by(0).unwrap();
}
let mut iter = xs.iter().chain(ys);
iter.advance_by(len).unwrap();
assert_eq!(iter.next(), None);
+ iter.advance_by(0).unwrap();
let mut iter = xs.iter().chain(ys);
assert_eq!(iter.advance_by(len + 1), Err(len));
+ iter.advance_by(0).unwrap();
}
test_chain(&[], &[]);
iter.advance_back_by(i).unwrap();
assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
assert_eq!(iter.advance_back_by(100), Err(len - i - 1));
+ iter.advance_back_by(0).unwrap();
}
for i in 0..xs.len() {
iter.advance_back_by(ys.len() + i).unwrap();
assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1));
+ iter.advance_back_by(0).unwrap();
}
let mut iter = xs.iter().chain(ys);
iter.advance_back_by(len).unwrap();
assert_eq!(iter.next_back(), None);
+ iter.advance_back_by(0).unwrap();
let mut iter = xs.iter().chain(ys);
assert_eq!(iter.advance_back_by(len + 1), Err(len));
+ iter.advance_back_by(0).unwrap();
}
test_chain(&[], &[]);
#[test]
fn test_flatten_advance_by() {
let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten();
+
it.advance_by(5).unwrap();
assert_eq!(it.next(), Some(5));
it.advance_by(9).unwrap();
assert_eq!(it.advance_by(usize::MAX), Err(9));
assert_eq!(it.advance_back_by(usize::MAX), Err(0));
+ it.advance_by(0).unwrap();
+ it.advance_back_by(0).unwrap();
assert_eq!(it.size_hint(), (0, Some(0)));
}
assert_eq!(it.nth(0), None);
}
+#[test]
+fn test_skip_advance_by() {
+ assert_eq!((0..0).skip(10).advance_by(0), Ok(()));
+ assert_eq!((0..0).skip(10).advance_by(1), Err(0));
+ assert_eq!((0u128..(usize::MAX as u128) + 1).skip(usize::MAX).advance_by(usize::MAX), Err(1));
+ assert_eq!((0u128..u128::MAX).skip(usize::MAX).advance_by(1), Ok(()));
+
+ assert_eq!((0..2).skip(1).advance_back_by(10), Err(1));
+ assert_eq!((0..0).skip(1).advance_back_by(0), Ok(()));
+}
+
#[test]
fn test_iterator_skip_count() {
let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
assert_eq!(it.nth_back(1), None);
}
+#[test]
+fn test_take_advance_by() {
+ let mut take = (0..10).take(3);
+ assert_eq!(take.advance_by(2), Ok(()));
+ assert_eq!(take.next(), Some(2));
+ assert_eq!(take.advance_by(1), Err(0));
+
+ assert_eq!((0..0).take(10).advance_by(0), Ok(()));
+ assert_eq!((0..0).take(10).advance_by(1), Err(0));
+ assert_eq!((0..10).take(4).advance_by(5), Err(4));
+
+ let mut take = (0..10).take(3);
+ assert_eq!(take.advance_back_by(2), Ok(()));
+ assert_eq!(take.next(), Some(0));
+ assert_eq!(take.advance_back_by(1), Err(0));
+
+ assert_eq!((0..2).take(1).advance_back_by(10), Err(1));
+ assert_eq!((0..0).take(1).advance_back_by(1), Err(0));
+ assert_eq!((0..0).take(1).advance_back_by(0), Ok(()));
+ assert_eq!((0..usize::MAX).take(100).advance_back_by(usize::MAX), Err(100));
+}
+
#[test]
fn test_iterator_take_short() {
let xs = [0, 1, 2, 3];
assert_eq!(r.advance_by(usize::MAX), Err(usize::MAX - 2));
+ r.advance_by(0).unwrap();
+ r.advance_back_by(0).unwrap();
+
let mut r = 0u128..u128::MAX;
r.advance_by(usize::MAX).unwrap();
#![feature(const_assume)]
#![feature(const_cell_into_inner)]
#![feature(const_convert)]
+#![feature(const_maybe_uninit_as_mut_ptr)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(const_ptr_read)]
#![feature(const_ptr_write)]
const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() };
assert_eq!(FOO, 42);
}
+
+#[test]
+fn const_maybe_uninit() {
+ use std::ptr;
+
+ #[derive(Debug, PartialEq)]
+ struct Foo {
+ x: u8,
+ y: u8,
+ }
+
+ const FIELD_BY_FIELD: Foo = unsafe {
+ let mut val = MaybeUninit::uninit();
+ init_y(&mut val); // order shouldn't matter
+ init_x(&mut val);
+ val.assume_init()
+ };
+
+ const fn init_x(foo: &mut MaybeUninit<Foo>) {
+ unsafe {
+ *ptr::addr_of_mut!((*foo.as_mut_ptr()).x) = 1;
+ }
+ }
+
+ const fn init_y(foo: &mut MaybeUninit<Foo>) {
+ unsafe {
+ *ptr::addr_of_mut!((*foo.as_mut_ptr()).y) = 2;
+ }
+ }
+
+ assert_eq!(FIELD_BY_FIELD, Foo { x: 1, y: 2 });
+}
assert_eq!(iter.as_slice(), &v[3..]);
iter.advance_by(2).unwrap();
assert_eq!(iter.as_slice(), &[]);
+ iter.advance_by(0).unwrap();
}
#[test]
assert_eq!(iter.as_slice(), &v[..v.len() - 3]);
iter.advance_back_by(2).unwrap();
assert_eq!(iter.as_slice(), &[]);
+ iter.advance_back_by(0).unwrap();
}
#[test]
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
-libc = { version = "0.2.106", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.52" }
+libc = { version = "0.2.108", default-features = false, features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "0.1.55" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] }
/// Ok(())
/// }
/// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
sys::fs::symlink_inner(original.as_ref(), link.as_ref(), false)
/// Ok(())
/// }
/// ```
+///
+/// # Limitations
+///
+/// Windows treats symlink creation as a [privileged action][symlink-security],
+/// therefore this function is likely to fail unless the user makes changes to
+/// their system to permit symlink creation. Users can try enabling Developer
+/// Mode, granting the `SeCreateSymbolicLinkPrivilege` privilege, or running
+/// the process as an administrator.
+///
+/// [symlink-security]: https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
sys::fs::symlink_inner(original.as_ref(), link.as_ref(), true)
#![cfg(target_os = "android")]
-use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
-use libc::{ftruncate, pread, pwrite};
+use libc::{c_int, sighandler_t};
-use super::{cvt, cvt_r, weak::weak};
-use crate::io;
+use super::weak::weak;
// The `log2` and `log2f` functions apparently appeared in android-18, or at
// least you can see they're not present in the android-17 header [1] and they
let f = f.expect("neither `signal` nor `bsd_signal` symbols found");
f(signum, handler)
}
-
-// The `ftruncate64` symbol apparently appeared in android-12, so we do some
-// dynamic detection to see if we can figure out whether `ftruncate64` exists.
-//
-// If it doesn't we just fall back to `ftruncate`, generating an error for
-// too-large values.
-#[cfg(target_pointer_width = "32")]
-pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
- weak!(fn ftruncate64(c_int, i64) -> c_int);
-
- unsafe {
- match ftruncate64.get() {
- Some(f) => cvt_r(|| f(fd, size as i64)).map(drop),
- None => {
- if size > i32::MAX as u64 {
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot truncate >2GB"))
- } else {
- cvt_r(|| ftruncate(fd, size as i32)).map(drop)
- }
- }
- }
- }
-}
-
-#[cfg(target_pointer_width = "64")]
-pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
- unsafe { cvt_r(|| ftruncate(fd, size as i64)).map(drop) }
-}
-
-#[cfg(target_pointer_width = "32")]
-pub unsafe fn cvt_pread64(
- fd: c_int,
- buf: *mut c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- use crate::convert::TryInto;
- weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
- pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
- if let Ok(o) = offset.try_into() {
- cvt(pread(fd, buf, count, o))
- } else {
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot pread >2GB"))
- }
- })
-}
-
-#[cfg(target_pointer_width = "32")]
-pub unsafe fn cvt_pwrite64(
- fd: c_int,
- buf: *const c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- use crate::convert::TryInto;
- weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
- pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
- if let Ok(o) = offset.try_into() {
- cvt(pwrite(fd, buf, count, o))
- } else {
- Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"cannot pwrite >2GB"))
- }
- })
-}
-
-#[cfg(target_pointer_width = "64")]
-pub unsafe fn cvt_pread64(
- fd: c_int,
- buf: *mut c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- cvt(pread(fd, buf, count, offset))
-}
-
-#[cfg(target_pointer_width = "64")]
-pub unsafe fn cvt_pwrite64(
- fd: c_int,
- buf: *const c_void,
- count: size_t,
- offset: i64,
-) -> io::Result<ssize_t> {
- cvt(pwrite(fd, buf, count, offset))
-}
}
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
- #[cfg(target_os = "android")]
- use super::android::cvt_pread64;
-
- #[cfg(not(target_os = "android"))]
- unsafe fn cvt_pread64(
- fd: c_int,
- buf: *mut c_void,
- count: usize,
- offset: i64,
- ) -> io::Result<isize> {
- #[cfg(not(target_os = "linux"))]
- use libc::pread as pread64;
- #[cfg(target_os = "linux")]
- use libc::pread64;
- cvt(pread64(fd, buf, count, offset))
- }
+ #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ use libc::pread as pread64;
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ use libc::pread64;
unsafe {
- cvt_pread64(
+ cvt(pread64(
self.as_raw_fd(),
buf.as_mut_ptr() as *mut c_void,
cmp::min(buf.len(), READ_LIMIT),
offset as i64,
- )
+ ))
.map(|n| n as usize)
}
}
}
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
- #[cfg(target_os = "android")]
- use super::android::cvt_pwrite64;
-
- #[cfg(not(target_os = "android"))]
- unsafe fn cvt_pwrite64(
- fd: c_int,
- buf: *const c_void,
- count: usize,
- offset: i64,
- ) -> io::Result<isize> {
- #[cfg(not(target_os = "linux"))]
- use libc::pwrite as pwrite64;
- #[cfg(target_os = "linux")]
- use libc::pwrite64;
- cvt(pwrite64(fd, buf, count, offset))
- }
+ #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ use libc::pwrite as pwrite64;
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ use libc::pwrite64;
unsafe {
- cvt_pwrite64(
+ cvt(pwrite64(
self.as_raw_fd(),
buf.as_ptr() as *const c_void,
cmp::min(buf.len(), READ_LIMIT),
offset as i64,
- )
+ ))
.map(|n| n as usize)
}
}
use libc::readdir_r as readdir64_r;
#[cfg(target_os = "android")]
use libc::{
- dirent as dirent64, fstat as fstat64, fstatat as fstatat64, lseek64, lstat as lstat64,
- open as open64, stat as stat64,
+ dirent as dirent64, fstat as fstat64, fstatat as fstatat64, ftruncate64, lseek64,
+ lstat as lstat64, off64_t, open as open64, stat as stat64,
};
#[cfg(not(any(
target_os = "linux",
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
- #[cfg(target_os = "android")]
- return crate::sys::android::ftruncate64(self.as_raw_fd(), size);
-
- #[cfg(not(target_os = "android"))]
- {
- use crate::convert::TryInto;
- let size: off64_t =
- size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
- cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop)
- }
+ use crate::convert::TryInto;
+ let size: off64_t =
+ size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
+ cvt_r(|| unsafe { ftruncate64(self.as_raw_fd(), size) }).map(drop)
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
} else if #[cfg(target_os = "macos")] {
// On MacOS, older versions (<=10.9) lack support for linkat while newer
// versions have it. We want to use linkat if it is available, so we use weak!
- // to check. `linkat` is preferable to `link` ecause it gives us a flag to
+ // to check. `linkat` is preferable to `link` because it gives us a flag to
// specify how symlinks should be handled. We pass 0 as the flags argument,
// meaning it shouldn't follow symlinks.
weak!(fn linkat(c_int, *const c_char, c_int, *const c_char, c_int) -> c_int);
static HAS_SENDFILE: AtomicBool = AtomicBool::new(true);
static HAS_SPLICE: AtomicBool = AtomicBool::new(true);
+ // Android builds use feature level 14, but the libc wrapper for splice is
+ // gated on feature level 21+, so we have to invoke the syscall directly.
+ #[cfg(target_os = "android")]
syscall! {
fn splice(
srcfd: libc::c_int,
) -> libc::ssize_t
}
+ #[cfg(target_os = "linux")]
+ use libc::splice;
+
match mode {
SpliceMode::Sendfile if !HAS_SENDFILE.load(Ordering::Relaxed) => {
return CopyResult::Fallback(0);
// res_init unconditionally, we call it only when we detect we're linking
// against glibc version < 2.26. (That is, when we both know its needed and
// believe it's thread-safe).
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn on_resolver_failure() {
use crate::sys;
}
}
-#[cfg(any(not(target_env = "gnu"), target_os = "vxworks"))]
+#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
fn on_resolver_failure() {}
#![allow(unused_imports)] // lots of cfg code here
-#[cfg(all(test, target_env = "gnu"))]
+#[cfg(test)]
mod tests;
use crate::os::unix::prelude::*;
unsafe { libc::getppid() as u32 }
}
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
pub fn glibc_version() -> Option<(usize, usize)> {
- if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) {
- parse_glibc_version(version_str)
- } else {
- None
- }
-}
-
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
-fn glibc_version_cstr() -> Option<&'static CStr> {
- weak! {
- fn gnu_get_libc_version() -> *const libc::c_char
+ extern "C" {
+ fn gnu_get_libc_version() -> *const libc::c_char;
}
- if let Some(f) = gnu_get_libc_version.get() {
- unsafe { Some(CStr::from_ptr(f())) }
+ let version_cstr = unsafe { CStr::from_ptr(gnu_get_libc_version()) };
+ if let Ok(version_str) = version_cstr.to_str() {
+ parse_glibc_version(version_str)
} else {
None
}
// Returns Some((major, minor)) if the string is a valid "x.y" version,
// ignoring any extra dot-separated parts. Otherwise return None.
-#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
let mut parsed_ints = version.split('.').map(str::parse::<usize>).fuse();
match (parsed_ints.next(), parsed_ints.next()) {
-use super::*;
-
#[test]
-#[cfg(not(target_os = "vxworks"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn test_glibc_version() {
// This mostly just tests that the weak linkage doesn't panic wildly...
- glibc_version();
+ super::glibc_version();
}
#[test]
-#[cfg(not(target_os = "vxworks"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn test_parse_glibc_version() {
let cases = [
("0.0", Some((0, 0))),
("foo.1", None),
];
for &(version_str, parsed) in cases.iter() {
- assert_eq!(parsed, parse_glibc_version(version_str));
+ assert_eq!(parsed, super::parse_glibc_version(version_str));
}
}
use crate::os::linux::process::PidFd;
#[cfg(target_os = "linux")]
-use crate::sys::weak::syscall;
+use crate::sys::weak::raw_syscall;
#[cfg(any(
target_os = "macos",
cgroup: u64,
}
- syscall! {
+ raw_syscall! {
fn clone3(cl_args: *mut clone_args, len: libc::size_t) -> libc::c_long
}
use crate::sys::{os, stack_overflow};
use crate::time::Duration;
-#[cfg(any(target_os = "linux", target_os = "solaris", target_os = "illumos"))]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
+use crate::sys::weak::dlsym;
+#[cfg(any(target_os = "solaris", target_os = "illumos"))]
use crate::sys::weak::weak;
#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
// We need that information to avoid blowing up when a small stack
// is created in an application with big thread-local storage requirements.
// See #6233 for rationale and details.
-#[cfg(target_os = "linux")]
-#[allow(deprecated)]
+#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
- weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
+ // We use dlsym to avoid an ELF version dependency on GLIBC_PRIVATE. (#23628)
+ // We shouldn't really be using such an internal symbol, but there's currently
+ // no other way to account for the TLS size.
+ dlsym!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
match __pthread_get_minstack.get() {
None => libc::PTHREAD_STACK_MIN,
}
}
-// No point in looking up __pthread_get_minstack() on non-glibc
-// platforms.
-#[cfg(all(not(target_os = "linux"), not(target_os = "netbsd")))]
+// No point in looking up __pthread_get_minstack() on non-glibc platforms.
+#[cfg(all(not(all(target_os = "linux", target_env = "gnu")), not(target_os = "netbsd")))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
libc::PTHREAD_STACK_MIN
}
//! detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
-//! really workable on Linux. Hence, use dlsym to get the symbol value at
+//! really workable with ELF. Otherwise, use dlsym to get the symbol value at
//! runtime. This is also done for compatibility with older versions of glibc,
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
//! we've been dynamically linked to the library the symbol comes from, but that
//!
//! A long time ago this used weak linkage for the __pthread_get_minstack
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
-//! dependency on libc6 (#23628).
+//! dependency on libc6 (#23628) because it is GLIBC_PRIVATE. We now use `dlsym`
+//! for a runtime lookup of that symbol to avoid the ELF versioned dependency.
// There are a variety of `#[cfg]`s controlling which targets are involved in
// each instance of `weak!` and `syscall!`. Rather than trying to unify all of
#![allow(dead_code, unused_macros)]
use crate::ffi::CStr;
-use crate::marker;
+use crate::marker::PhantomData;
use crate::mem;
use crate::sync::atomic::{self, AtomicUsize, Ordering};
+// We can use true weak linkage on ELF targets.
+#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub(crate) macro weak {
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
- #[allow(non_upper_case_globals)]
- static $name: crate::sys::weak::Weak<unsafe extern "C" fn($($t),*) -> $ret> =
- crate::sys::weak::Weak::new(concat!(stringify!($name), '\0'));
+ let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
+ extern "C" {
+ #[linkage = "extern_weak"]
+ static $name: *const libc::c_void;
+ }
+ #[allow(unused_unsafe)]
+ ExternWeak::new(unsafe { $name })
+ };
)
}
-pub struct Weak<F> {
+// On non-ELF targets, use the dlsym approximation of weak linkage.
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+pub(crate) use self::dlsym as weak;
+
+pub(crate) struct ExternWeak<F> {
+ weak_ptr: *const libc::c_void,
+ _marker: PhantomData<F>,
+}
+
+impl<F> ExternWeak<F> {
+ #[inline]
+ pub(crate) fn new(weak_ptr: *const libc::c_void) -> Self {
+ ExternWeak { weak_ptr, _marker: PhantomData }
+ }
+}
+
+impl<F> ExternWeak<F> {
+ #[inline]
+ pub(crate) fn get(&self) -> Option<F> {
+ unsafe {
+ if self.weak_ptr.is_null() {
+ None
+ } else {
+ Some(mem::transmute_copy::<*const libc::c_void, F>(&self.weak_ptr))
+ }
+ }
+ }
+}
+
+pub(crate) macro dlsym {
+ (fn $name:ident($($t:ty),*) -> $ret:ty) => (
+ static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> =
+ DlsymWeak::new(concat!(stringify!($name), '\0'));
+ let $name = &DLSYM;
+ )
+}
+
+pub(crate) struct DlsymWeak<F> {
name: &'static str,
addr: AtomicUsize,
- _marker: marker::PhantomData<F>,
+ _marker: PhantomData<F>,
}
-impl<F> Weak<F> {
- pub const fn new(name: &'static str) -> Weak<F> {
- Weak { name, addr: AtomicUsize::new(1), _marker: marker::PhantomData }
+impl<F> DlsymWeak<F> {
+ pub(crate) const fn new(name: &'static str) -> Self {
+ DlsymWeak { name, addr: AtomicUsize::new(1), _marker: PhantomData }
}
- pub fn get(&self) -> Option<F> {
- assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+ #[inline]
+ pub(crate) fn get(&self) -> Option<F> {
unsafe {
// Relaxed is fine here because we fence before reading through the
// pointer (see the comment below).
// Cold because it should only happen during first-time initalization.
#[cold]
unsafe fn initialize(&self) -> Option<F> {
+ assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+
let val = fetch(self.name);
// This synchronizes with the acquire fence in `get`.
self.addr.store(val, Ordering::Release);
pub(crate) macro syscall {
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
unsafe fn $name($($arg_name: $t),*) -> $ret {
- use super::os;
-
weak! { fn $name($($t),*) -> $ret }
if let Some(fun) = $name.get() {
fun($($arg_name),*)
} else {
- os::set_errno(libc::ENOSYS);
+ super::os::set_errno(libc::ENOSYS);
-1
}
}
pub(crate) macro syscall {
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
unsafe fn $name($($arg_name:$t),*) -> $ret {
- use weak;
- // This looks like a hack, but concat_idents only accepts idents
- // (not paths).
- use libc::*;
-
weak! { fn $name($($t),*) -> $ret }
// Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
if let Some(fun) = $name.get() {
fun($($arg_name),*)
} else {
+ // This looks like a hack, but concat_idents only accepts idents
+ // (not paths).
+ use libc::*;
+
syscall(
concat_idents!(SYS_, $name),
$($arg_name),*
}
)
}
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub(crate) macro raw_syscall {
+ (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
+ unsafe fn $name($($arg_name:$t),*) -> $ret {
+ // This looks like a hack, but concat_idents only accepts idents
+ // (not paths).
+ use libc::*;
+
+ syscall(
+ concat_idents!(SYS_, $name),
+ $($arg_name),*
+ ) as $ret
+ }
+ )
+}
/// The purpose of this API is to provide an easy and portable way to query
/// the default amount of parallelism the program should use. Among other things it
/// does not expose information on NUMA regions, does not account for
-/// differences in (co)processor capabilities, and will not modify the program's
-/// global state in order to more accurately query the amount of available
-/// parallelism.
+/// differences in (co)processor capabilities or current system load,
+/// and will not modify the program's global state in order to more accurately
+/// query the amount of available parallelism.
+///
+/// Where both fixed steady-state and burst limits are available the steady-state
+/// capacity will be used to ensure more predictable latencies.
///
/// Resource limits can be changed during the runtime of a program, therefore the value is
/// not cached and instead recomputed every time this function is called. It should not be
// NOTE: The check for the empty directory is here because when running x.py the first time,
// the submodule won't be checked out. Check it out now so we can build it.
- if !channel::GitInfo::new(false, relative_path).is_git() && !dir_is_empty(&absolute_path) {
+ if !channel::GitInfo::new(false, &absolute_path).is_git() && !dir_is_empty(&absolute_path) {
return;
}
that you must write the `(())` in one sequence without intermediate whitespace
so that `rustdoc` understands you want an implicit `Result`-returning function.
+## Showing warnings in doctests
+
+You can show warnings in doctests by running `rustdoc --test --test-args=--show-output`
+(or, if you're using cargo, `cargo test --doc -- --show-output`).
+By default, this will still hide `unused` warnings, since so many examples use private functions;
+you can add `#![warn(unused)]` to the top of your example if you want to see unused variables or dead code warnings.
+You can also use [`#![doc(test(attr(warn(unused))))]`][test-attr] in the crate root to enable warnings globally.
+
+[test-attr]: ./the-doc-attribute.md#testattr
+
## Documenting macros
Here’s an example of documenting a macro:
specially cache them. This flag will rename all these files in the output to include the suffix in
the filename. For example, `light.css` would become `light-suf.css` with the above command.
-### `--display-doctest-warnings`: display warnings when documenting or running documentation tests
-
-Using this flag looks like this:
-
-```bash
-$ rustdoc src/lib.rs -Z unstable-options --display-doctest-warnings
-$ rustdoc --test src/lib.rs -Z unstable-options --display-doctest-warnings
-```
-
-The intent behind this flag is to allow the user to see warnings that occur within their library or
-their documentation tests, which are usually suppressed. However, [due to a
-bug][issue-display-warnings], this flag doesn't 100% work as intended. See the linked issue for
-details.
-
-[issue-display-warnings]: https://github.com/rust-lang/rust/issues/41574
-
### `--extern-html-root-url`: control how rustdoc links to non-local crates
Using this flag looks like this:
When `-Z instrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by:
- Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed.
-- Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 4_, supported _only_ in LLVM 11 and up), to define the code regions (start and end positions in the source code) being counted.
+- Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 5_, if compiling with LLVM 12, or _Version 6_, if compiling with LLVM 13 or higher), to define the code regions (start and end positions in the source code) being counted.
When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats.
## Installing LLVM coverage tools
-LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 11 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.):
+LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 12 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.):
- The LLVM tools may be installed (or installable) directly to your OS (such as via `apt-get`, for Linux).
- If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`.
_ => false,
}
})
- .map(|p| p.fold_with(&mut replacer));
+ .map(|p| p.fold_with(&mut replacer).into_ok());
let mut generic_params =
(tcx.generics_of(item_def_id), tcx.explicit_predicates_of(item_def_id))
self.tcx
}
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- (match *r {
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
+ Ok((match *r {
ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
_ => None,
})
- .unwrap_or_else(|| r.super_fold_with(self))
+ .unwrap_or_else(|| r.super_fold_with(self).into_ok()))
}
}
}
let impl_item = match did.as_local() {
- Some(did) => {
- let hir_id = tcx.hir().local_def_id_to_hir_id(did);
- match &tcx.hir().expect_item(hir_id).kind {
- hir::ItemKind::Impl(impl_) => Some(impl_),
- _ => panic!("`DefID` passed to `build_impl` is not an `impl"),
- }
- }
+ Some(did) => match &tcx.hir().expect_item(did).kind {
+ hir::ItemKind::Impl(impl_) => Some(impl_),
+ _ => panic!("`DefID` passed to `build_impl` is not an `impl"),
+ },
None => None,
};
use utils::*;
-crate use utils::{get_auto_trait_and_blanket_impls, krate, register_res};
-
-crate use self::types::FnRetTy::*;
-crate use self::types::ItemKind::*;
-crate use self::types::SelfTy::*;
-crate use self::types::Type::*;
-crate use self::types::Visibility::{Inherited, Public};
crate use self::types::*;
+crate use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res};
crate trait Clean<T> {
fn clean(&self, cx: &mut DocContext<'_>) -> T;
let what_rustc_thinks =
Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
- let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(self.hir_id()));
+ let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_did(self.hir_id()));
if let hir::ItemKind::Impl(impl_) = &parent_item.kind {
if impl_.of_trait.is_some() {
// Trait impl items always inherit the impl's visibility --
let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
// Substitute private type aliases
let Some(def_id) = def_id.as_local() else { return None };
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
let alias = if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
- &cx.tcx.hir().expect_item(hir_id).kind
+ &cx.tcx.hir().expect_item(def_id).kind
} else {
return None;
};
};
inline::record_extern_fqn(cx, did, kind);
let path = external_path(cx, did, false, vec![], substs);
- ResolvedPath { path }
+ Type::Path { path }
}
ty::Foreign(did) => {
inline::record_extern_fqn(cx, did, ItemType::ForeignType);
let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
- ResolvedPath { path }
+ Type::Path { path }
}
ty::Dynamic(obj, ref reg) => {
// HACK: pick the first `did` as the `did` of the trait object. Someone
use crate::clean::cfg::Cfg;
use crate::clean::external_path;
use crate::clean::inline::{self, print_inlined_const};
-use crate::clean::types::Type::{QPath, ResolvedPath};
use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
use crate::clean::Clean;
use crate::core::DocContext;
use crate::html::render::cache::ExternalLocation;
use crate::html::render::Context;
-use self::FnRetTy::*;
-use self::ItemKind::*;
-use self::SelfTy::*;
-use self::Type::*;
+crate use self::FnRetTy::*;
+crate use self::ItemKind::*;
+crate use self::SelfTy::*;
+crate use self::Type::{
+ Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
+ RawPointer, Slice, Tuple,
+};
+crate use self::Visibility::{Inherited, Public};
crate type ItemIdSet = FxHashSet<ItemId>;
crate enum Type {
/// A named type, which could be a trait.
///
- /// This is mostly Rustdoc's version of [`hir::Path`]. It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
- ResolvedPath { path: Path },
+ /// This is mostly Rustdoc's version of [`hir::Path`].
+ /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
+ Path { path: Path },
/// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
DynTrait(Vec<PolyTrait>, Option<Lifetime>),
/// A type parameter.
rustc_data_structures::static_assert_size!(Type, 72);
impl Type {
+ /// When comparing types for equality, it can help to ignore `&` wrapping.
+ crate fn without_borrowed_ref(&self) -> &Type {
+ let mut result = self;
+ while let Type::BorrowedRef { type_, .. } = result {
+ result = &*type_;
+ }
+ result
+ }
+
+ /// Check if two types are "potentially the same".
+ /// This is different from `Eq`, because it knows that things like
+ /// `Placeholder` are possible matches for everything.
+ crate fn is_same(&self, other: &Self, cache: &Cache) -> bool {
+ match (self, other) {
+ // Recursive cases.
+ (Type::Tuple(a), Type::Tuple(b)) => {
+ a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(&b, cache))
+ }
+ (Type::Slice(a), Type::Slice(b)) => a.is_same(&b, cache),
+ (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(&b, cache),
+ (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
+ mutability == b_mutability && type_.is_same(&b_type_, cache)
+ }
+ (
+ Type::BorrowedRef { mutability, type_, .. },
+ Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
+ ) => mutability == b_mutability && type_.is_same(&b_type_, cache),
+ // Placeholders and generics are equal to all other types.
+ (Type::Infer, _) | (_, Type::Infer) => true,
+ (Type::Generic(_), _) | (_, Type::Generic(_)) => true,
+ // Other cases, such as primitives, just use recursion.
+ (a, b) => a
+ .def_id(cache)
+ .and_then(|a| Some((a, b.def_id(cache)?)))
+ .map(|(a, b)| a == b)
+ .unwrap_or(false),
+ }
+ }
+
crate fn primitive_type(&self) -> Option<PrimitiveType> {
match *self {
Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p),
/// Checks if this is a `T::Name` path for an associated type.
crate fn is_assoc_ty(&self) -> bool {
match self {
- ResolvedPath { path, .. } => path.is_assoc_ty(),
+ Type::Path { path, .. } => path.is_assoc_ty(),
_ => false,
}
}
crate fn generics(&self) -> Option<Vec<&Type>> {
match self {
- ResolvedPath { path, .. } => path.generics(),
+ Type::Path { path, .. } => path.generics(),
_ => None,
}
}
fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
let t: PrimitiveType = match *self {
- ResolvedPath { ref path } => return Some(path.def_id()),
+ Type::Path { ref path } => return Some(path.def_id()),
DynTrait(ref bounds, _) => return Some(bounds[0].trait_.def_id()),
Primitive(p) => return cache.and_then(|c| c.primitive_locations.get(&p).cloned()),
BorrowedRef { type_: box Generic(..), .. } => PrimitiveType::Reference,
use crate::clean::blanket_impl::BlanketImplFinder;
use crate::clean::{
inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item,
- ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type,
- TypeBinding, Visibility,
+ ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) {
inline::build_impl(cx, None, did, None, ret);
}
- } else if let ResolvedPath { path } = target {
+ } else if let Type::Path { path } = target {
let did = path.def_id();
if !did.is_local() {
inline::build_impls(cx, None, did, None, ret);
Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
_ => {
let _ = register_res(cx, path.res);
- ResolvedPath { path }
+ Type::Path { path }
}
}
}
///
/// Be aware: This option can come both from the CLI and from crate attributes!
crate manual_passes: Vec<String>,
- /// Whether to display warnings during doc generation or while gathering doctests. By default,
- /// all non-rustdoc-specific lints are allowed when generating docs.
- crate display_doctest_warnings: bool,
/// Whether to run the `calculate-doc-coverage` pass, which counts the number of public items
/// with and without documentation.
crate show_coverage: bool,
.field("persist_doctests", &self.persist_doctests)
.field("default_passes", &self.default_passes)
.field("manual_passes", &self.manual_passes)
- .field("display_doctest_warnings", &self.display_doctest_warnings)
.field("show_coverage", &self.show_coverage)
.field("crate_version", &self.crate_version)
.field("render_options", &self.render_options)
))
.emit();
}
- themes.push(StylePath { path: theme_file, disabled: true });
+ themes.push(StylePath { path: theme_file });
}
}
let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
let playground_url = matches.opt_str("playground-url");
let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
- let display_doctest_warnings = matches.opt_present("display-doctest-warnings");
let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance");
let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default();
let enable_minification = !matches.opt_present("disable-minification");
test_args,
default_passes,
manual_passes,
- display_doctest_warnings,
show_coverage,
crate_version,
test_run_directory,
crate struct TestOptions {
/// Whether to disable the default `extern crate my_crate;` when creating doctests.
crate no_crate_inject: bool,
- /// Whether to emit compilation warnings when compiling doctests. Setting this will suppress
- /// the default `#![allow(unused)]`.
- crate display_doctest_warnings: bool,
/// Additional crate-level attributes to add to doctests.
crate attrs: Vec<String>,
}
}
});
+ debug!(?lint_opts);
+
let crate_types =
if options.proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
maybe_sysroot: options.maybe_sysroot.clone(),
search_paths: options.libs.clone(),
crate_types,
- lint_opts: if !options.display_doctest_warnings { lint_opts } else { vec![] },
+ lint_opts,
lint_cap: Some(options.lint_cap.unwrap_or(lint::Forbid)),
cg: options.codegen_options.clone(),
externs: options.externs.clone(),
};
let test_args = options.test_args.clone();
- let display_doctest_warnings = options.display_doctest_warnings;
let nocapture = options.nocapture;
let externs = options.externs.clone();
let json_unused_externs = options.json_unused_externs;
let collector = global_ctxt.enter(|tcx| {
let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID);
- let mut opts = scrape_test_config(crate_attrs);
- opts.display_doctest_warnings |= options.display_doctest_warnings;
+ let opts = scrape_test_config(crate_attrs);
let enable_per_target_ignores = options.enable_per_target_ignores;
let mut collector = Collector::new(
tcx.crate_name(LOCAL_CRATE),
Err(ErrorReported) => return Err(ErrorReported),
};
- run_tests(test_args, nocapture, display_doctest_warnings, tests);
+ run_tests(test_args, nocapture, tests);
// Collect and warn about unused externs, but only if we've gotten
// reports for each doctest
Ok(())
}
-crate fn run_tests(
- mut test_args: Vec<String>,
- nocapture: bool,
- display_doctest_warnings: bool,
- tests: Vec<test::TestDescAndFn>,
-) {
+crate fn run_tests(mut test_args: Vec<String>, nocapture: bool, tests: Vec<test::TestDescAndFn>) {
test_args.insert(0, "rustdoctest".to_string());
if nocapture {
test_args.push("--nocapture".to_string());
}
- test::test_main(
- &test_args,
- tests,
- Some(test::Options::new().display_output(display_doctest_warnings)),
- );
+ test::test_main(&test_args, tests, None);
}
// Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade.
fn scrape_test_config(attrs: &[ast::Attribute]) -> TestOptions {
use rustc_ast_pretty::pprust;
- let mut opts =
- TestOptions { no_crate_inject: false, display_doctest_warnings: false, attrs: Vec::new() };
+ let mut opts = TestOptions { no_crate_inject: false, attrs: Vec::new() };
let test_attrs: Vec<_> = attrs
.iter()
let mut prog = String::new();
let mut supports_color = false;
- if opts.attrs.is_empty() && !opts.display_doctest_warnings {
+ if opts.attrs.is_empty() {
// If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some
// lints that are commonly triggered in doctests. The crate-level test attributes are
// commonly used to make tests fail in case they trigger warnings, so having this there in
fn make_test_no_crate_inject() {
// Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip
// adding it anyway.
- let opts =
- TestOptions { no_crate_inject: true, display_doctest_warnings: false, attrs: vec![] };
+ let opts = TestOptions { no_crate_inject: true, attrs: vec![] };
let input = "use asdf::qwop;
assert_eq!(2+2, 4);";
let expected = "#![allow(unused)]
assert_eq!((output, len), (expected, 1));
}
-#[test]
-fn make_test_display_doctest_warnings() {
- // If the user is asking to display doctest warnings, suppress the default `allow(unused)`.
- let mut opts = TestOptions::default();
- opts.display_doctest_warnings = true;
- let input = "assert_eq!(2+2, 4);";
- let expected = "fn main() {
-assert_eq!(2+2, 4);
-}"
- .to_string();
- let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None);
- assert_eq!((output, len), (expected, 1));
-}
-
#[test]
fn make_test_issues_21299_33731() {
let opts = TestOptions::default();
match $e {
Some(e) => e,
None => {
- return Err(Error::new(io::Error::new(io::ErrorKind::Other, "not found"), $file));
+ return Err(<crate::error::Error as crate::docfs::PathError>::new(
+ io::Error::new(io::ErrorKind::Other, "not found"),
+ $file,
+ ));
}
}
}};
#[derive(Default)]
crate struct Cache {
/// Maps a type ID to all known implementations for that type. This is only
- /// recognized for intra-crate `ResolvedPath` types, and is used to print
+ /// recognized for intra-crate [`clean::Type::Path`]s, and is used to print
/// out extra documentation on the page of an enum/struct.
///
/// The values of the map are a list of implementations and documentation
clean::ImplItem(ref i) => {
self.cache.parent_is_trait_impl = i.trait_.is_some();
match i.for_ {
- clean::ResolvedPath { ref path } => {
+ clean::Type::Path { ref path } => {
self.cache.parent_stack.push(path.def_id());
true
}
// Note: matching twice to restrict the lifetime of the `i` borrow.
let mut dids = FxHashSet::default();
match i.for_ {
- clean::ResolvedPath { ref path }
- | clean::BorrowedRef { type_: box clean::ResolvedPath { ref path }, .. } => {
+ clean::Type::Path { ref path }
+ | clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. } => {
dids.insert(path.def_id());
}
clean::DynTrait(ref bounds, _)
}
}
-/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
-/// rendering function with the necessary arguments for linking to a local path.
+/// Used to render a [`clean::Path`].
fn resolved_path<'cx>(
w: &mut fmt::Formatter<'_>,
did: DefId,
match *t {
clean::Generic(name) => write!(f, "{}", name),
- clean::ResolvedPath { ref path } => {
+ clean::Type::Path { ref path } => {
// Paths like `T::Output` and `Self::Output` should be rendered with all segments.
let did = path.def_id();
resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx)
use rustc_data_structures::fx::FxHashMap;
+use crate::error::Error;
use crate::externalfiles::ExternalHtml;
-use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};
static_root_path: &'a str,
page: &'a Page<'a>,
layout: &'a Layout,
- style_files: String,
+ themes: Vec<String>,
sidebar: String,
content: String,
krate_with_trailing_slash: String,
+ crate rustdoc_version: &'a str,
}
crate fn render<T: Print, S: Print>(
) -> String {
let static_root_path = page.get_static_root_path();
let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
- let style_files = style_files
+ let mut themes: Vec<String> = style_files
.iter()
- .filter_map(|t| t.path.file_stem().map(|stem| (stem, t.disabled)))
- .filter_map(|t| t.0.to_str().map(|path| (path, t.1)))
- .map(|t| {
- format!(
- r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
- Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
- if t.1 { "disabled" } else { "" },
- if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
- )
- })
- .collect::<String>();
+ .map(StylePath::basename)
+ .collect::<Result<_, Error>>()
+ .unwrap_or_default();
+ themes.sort();
+ let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version");
let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
let sidebar = Buffer::html().to_display(sidebar);
let teractx = tera::Context::from_serialize(PageLayout {
static_root_path,
page,
layout,
- style_files,
+ themes,
sidebar,
content,
krate_with_trailing_slash,
+ rustdoc_version,
})
.unwrap();
templates.render("page.html", &teractx).unwrap()
fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<Symbol> {
match *clean_type {
- clean::ResolvedPath { ref path, .. } => {
+ clean::Type::Path { ref path, .. } => {
let path_segment = path.segments.last().unwrap();
Some(path_segment.name)
}
let mut ty_generics = Vec::new();
for bound in bound.get_bounds().unwrap_or(&[]) {
if let Some(path) = bound.get_trait_path() {
- let ty = Type::ResolvedPath { path };
+ let ty = Type::Path { path };
get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics, cache);
}
}
// by the browser as the theme stylesheet. The theme system (hackily) works by
// changing the href to this stylesheet. All other themes are disabled to
// prevent rule conflicts
- scx.style_files.push(StylePath { path: PathBuf::from("light.css"), disabled: false });
- scx.style_files.push(StylePath { path: PathBuf::from("dark.css"), disabled: true });
- scx.style_files.push(StylePath { path: PathBuf::from("ayu.css"), disabled: true });
+ scx.style_files.push(StylePath { path: PathBuf::from("light.css") });
+ scx.style_files.push(StylePath { path: PathBuf::from("dark.css") });
+ scx.style_files.push(StylePath { path: PathBuf::from("ayu.css") });
let dst = output;
scx.ensure_dir(&dst)?;
page.description = "Settings of Rustdoc";
page.root_path = "./";
- let mut style_files = self.shared.style_files.clone();
let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
- style_files.push(StylePath { path: PathBuf::from("settings.css"), disabled: false });
+ let theme_names: Vec<String> = self
+ .shared
+ .style_files
+ .iter()
+ .map(StylePath::basename)
+ .collect::<Result<_, Error>>()?;
let v = layout::render(
&self.shared.templates,
&self.shared.layout,
settings(
self.shared.static_root_path.as_deref().unwrap_or("./"),
&self.shared.resource_suffix,
- &self.shared.style_files,
+ theme_names,
)?,
- &style_files,
+ &self.shared.style_files,
);
self.shared.fs.write(settings_file, v)?;
if let Some(ref redirections) = self.shared.redirections {
use serde::{Serialize, Serializer};
use crate::clean::{self, ItemId, RenderedLink, SelfTy};
-use crate::docfs::PathError;
use crate::error::Error;
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
crate struct StylePath {
/// The path to the theme
crate path: PathBuf,
- /// What the `disabled` attribute should be set to in the HTML tag
- crate disabled: bool,
+}
+
+impl StylePath {
+ pub fn basename(&self) -> Result<String, Error> {
+ Ok(try_none!(try_none!(self.path.file_stem(), &self.path).to_str(), &self.path).to_string())
+ }
}
fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
js_data_name: &'static str,
description: &'static str,
default_value: &'static str,
- options: Vec<(String, String)>,
+ options: Vec<String>,
},
}
options
.iter()
.map(|opt| format!(
- "<option value=\"{}\" {}>{}</option>",
- opt.0,
- if opt.0 == default_value { "selected" } else { "" },
- opt.1,
+ "<option value=\"{name}\" {}>{name}</option>",
+ if opt == default_value { "selected" } else { "" },
+ name = opt,
))
.collect::<String>(),
root_path,
}
}
-fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<String, Error> {
- let theme_names: Vec<(String, String)> = themes
- .iter()
- .map(|entry| {
- let theme =
- try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path)
- .to_string();
-
- Ok((theme.clone(), theme))
- })
- .collect::<Result<_, Error>>()?;
-
+fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<String, Error> {
// (id, explanation, default value)
let settings: &[Setting] = &[
(
<span class=\"in-band\">Rustdoc settings</span>\
</h1>\
<div class=\"settings\">{}</div>\
- <script src=\"{}settings{}.js\"></script>",
+ <link rel=\"stylesheet\" href=\"{root_path}settings{suffix}.css\">\
+ <script src=\"{root_path}settings{suffix}.js\"></script>",
settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
- root_path,
- suffix
+ root_path = root_path,
+ suffix = suffix
))
}
| SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
(mutability == Mutability::Mut, false, false)
}
- SelfTy::SelfExplicit(clean::ResolvedPath { path }) => {
+ SelfTy::SelfExplicit(clean::Type::Path { path }) => {
(false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
}
SelfTy::SelfValue => (false, false, true),
fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
let mut out = Buffer::html();
- if let Some(did) = decl.output.as_return().and_then(|t| t.def_id(cx.cache())) {
+ if let Some((did, ty)) = decl.output.as_return().and_then(|t| Some((t.def_id(cx.cache())?, t)))
+ {
if let Some(impls) = cx.cache().impls.get(&did) {
for i in impls {
let impl_ = i.inner_impl();
+ if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache())
+ {
+ // Two different types might have the same did,
+ // without actually being the same.
+ continue;
+ }
if let Some(trait_) = &impl_.trait_ {
let trait_did = trait_.def_id();
}
match ty {
- clean::Type::ResolvedPath { path } => process_path(path.def_id()),
+ clean::Type::Path { path } => process_path(path.def_id()),
clean::Type::Tuple(tys) => {
work.extend(tys.into_iter());
}
let mut implementor_dups: FxHashMap<Symbol, (DefId, bool)> = FxHashMap::default();
for implementor in implementors {
match implementor.inner_impl().for_ {
- clean::ResolvedPath { ref path }
- | clean::BorrowedRef { type_: box clean::ResolvedPath { ref path }, .. }
+ clean::Type::Path { ref path }
+ | clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. }
if !path.is_assoc_ty() =>
{
let did = path.def_id();
// If there's already another implementor that has the same abridged name, use the
// full path, for example in `std::iter::ExactSizeIterator`
let use_absolute = match implementor.inner_impl().for_ {
- clean::ResolvedPath { ref path, .. }
- | clean::BorrowedRef { type_: box clean::ResolvedPath { ref path, .. }, .. }
+ clean::Type::Path { ref path, .. }
+ | clean::BorrowedRef { type_: box clean::Type::Path { ref path, .. }, .. }
if !path.is_assoc_ty() =>
{
implementor_dups[&path.last()].1
the type was too big.</p>"
);
}
+ Err(LayoutError::NormalizationFailure(_, _)) => {
+ writeln!(
+ w,
+ "<p><strong>Note:</strong> Encountered an error during type layout; \
+ the type failed to be normalized.</p>"
+ )
+ }
}
writeln!(w, "</div>");
cx.write_shared(SharedResource::InvocationSpecific { basename: p }, content, &options.emit)
};
- fn add_background_image_to_css(
- cx: &Context<'_>,
- css: &mut String,
- rule: &str,
- file: &'static str,
- ) {
- css.push_str(&format!(
- "{} {{ background-image: url({}); }}",
- rule,
- SharedResource::ToolchainSpecific { basename: file }
+ // Given "foo.svg", return e.g. "url(\"foo1.58.0.svg\")"
+ fn ver_url(cx: &Context<'_>, basename: &'static str) -> String {
+ format!(
+ "url(\"{}\")",
+ SharedResource::ToolchainSpecific { basename }
.path(cx)
.file_name()
.unwrap()
.to_str()
.unwrap()
- ))
+ )
}
- // Add all the static files. These may already exist, but we just
- // overwrite them anyway to make sure that they're fresh and up-to-date.
- let mut rustdoc_css = static_files::RUSTDOC_CSS.to_owned();
- add_background_image_to_css(
- cx,
- &mut rustdoc_css,
- "details.undocumented[open] > summary::before, \
- details.rustdoc-toggle[open] > summary::before, \
- details.rustdoc-toggle[open] > summary.hideme::before",
- "toggle-minus.svg",
- );
- add_background_image_to_css(
+ // We use the AUTOREPLACE mechanism to inject into our static JS and CSS certain
+ // values that are only known at doc build time. Since this mechanism is somewhat
+ // surprising when reading the code, please limit it to rustdoc.css.
+ write_minify(
+ "rustdoc.css",
+ static_files::RUSTDOC_CSS
+ .replace(
+ "/* AUTOREPLACE: */url(\"toggle-minus.svg\")",
+ &ver_url(cx, "toggle-minus.svg"),
+ )
+ .replace("/* AUTOREPLACE: */url(\"toggle-plus.svg\")", &ver_url(cx, "toggle-plus.svg"))
+ .replace("/* AUTOREPLACE: */url(\"down-arrow.svg\")", &ver_url(cx, "down-arrow.svg")),
cx,
- &mut rustdoc_css,
- "details.undocumented > summary::before, details.rustdoc-toggle > summary::before",
- "toggle-plus.svg",
- );
- write_minify("rustdoc.css", rustdoc_css, cx, options)?;
+ options,
+ )?;
// Add all the static files. These may already exist, but we just
// overwrite them anyway to make sure that they're fresh and up-to-date.
let mut themes: FxHashSet<String> = FxHashSet::default();
for entry in &cx.shared.style_files {
- let theme = try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path);
+ let theme = entry.basename()?;
let extension =
try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path);
// Handle the official themes
- match theme {
+ match theme.as_str() {
"light" => write_minify("light.css", static_files::themes::LIGHT, cx, options)?,
"dark" => write_minify("dark.css", static_files::themes::DARK, cx, options)?,
"ayu" => write_minify("ayu.css", static_files::themes::AYU, cx, options)?,
let mut themes: Vec<&String> = themes.iter().collect();
themes.sort();
- // FIXME: this should probably not be a toolchain file since it depends on `--theme`.
- // But it seems a shame to copy it over and over when it's almost always the same.
- // Maybe we can change the representation to move this out of main.js?
- write_minify(
- "main.js",
- static_files::MAIN_JS
- .replace(
- "/* INSERT THEMES HERE */",
- &format!(" = {}", serde_json::to_string(&themes).unwrap()),
- )
- .replace(
- "/* INSERT RUSTDOC_VERSION HERE */",
- &format!(
- "rustdoc {}",
- rustc_interface::util::version_str().unwrap_or("unknown version")
- ),
- ),
- cx,
- options,
- )?;
+ write_minify("main.js", static_files::MAIN_JS, cx, options)?;
write_minify("search.js", static_files::SEARCH_JS, cx, options)?;
write_minify("settings.js", static_files::SETTINGS_JS, cx, options)?;
write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT, cx, options)?;
}
- {
- write_minify(
- "storage.js",
- format!(
- "var resourcesSuffix = \"{}\";{}",
- cx.shared.resource_suffix,
- static_files::STORAGE_JS
- ),
- cx,
- options,
- )?;
- }
+ write_minify("storage.js", static_files::STORAGE_JS, cx, options)?;
if cx.shared.layout.scrape_examples_extension {
cx.write_minify(
background-color: transparent;
background-size: 20px;
background-position: calc(100% - 1px) 56%;
+ background-image: /* AUTOREPLACE: */url("down-arrow.svg");
}
.search-container > .top-button {
position: absolute;
margin-top: 3px;
}
-.docblock > .section-header:first-child {
+.top-doc .docblock > .section-header:first-child {
margin-left: 15px;
- margin-top: 0;
}
-
-.docblock > .section-header:first-child:hover > a:before {
+.top-doc .docblock > .section-header:first-child:hover > a:before {
left: -10px;
}
+.docblock > .section-header:first-child {
+ margin-top: 0;
+}
+
:target > code, :target > .code-header {
opacity: 1;
}
display: none;
}
+details.undocumented[open] > summary::before,
+details.rustdoc-toggle[open] > summary::before,
+details.rustdoc-toggle[open] > summary.hideme::before {
+ background-image: /* AUTOREPLACE: */url("toggle-minus.svg");
+}
+
+details.undocumented > summary::before, details.rustdoc-toggle > summary::before {
+ background-image: /* AUTOREPLACE: */url("toggle-plus.svg");
+}
+
details.rustdoc-toggle[open] > summary::before,
details.rustdoc-toggle[open] > summary.hideme::before {
width: 17px;
};
}
-(function () {
- var rustdocVars = document.getElementById("rustdoc-vars");
- if (rustdocVars) {
- window.rootPath = rustdocVars.attributes["data-root-path"].value;
- window.currentCrate = rustdocVars.attributes["data-current-crate"].value;
- window.searchJS = rustdocVars.attributes["data-search-js"].value;
- window.searchIndexJS = rustdocVars.attributes["data-search-index-js"].value;
+// Get a value from the rustdoc-vars div, which is used to convey data from
+// Rust to the JS. If there is no such element, return null.
+function getVar(name) {
+ var el = document.getElementById("rustdoc-vars");
+ if (el) {
+ return el.attributes["data-" + name].value;
+ } else {
+ return null;
}
+}
+
+// Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL
+// for a resource under the root-path, with the resource-suffix.
+function resourcePath(basename, extension) {
+ return getVar("root-path") + basename + getVar("resource-suffix") + extension;
+}
+
+
+(function () {
+ window.rootPath = getVar("root-path");
+ window.currentCrate = getVar("current-crate");
+ window.searchJS = resourcePath("search", ".js");
+ window.searchIndexJS = resourcePath("search-index", ".js");
var sidebarVars = document.getElementById("sidebar-vars");
if (sidebarVars) {
window.sidebarCurrent = {
(function () {
var themeChoices = getThemesElement();
var themePicker = getThemePickerElement();
- var availableThemes/* INSERT THEMES HERE */;
+ var availableThemes = getVar("themes").split(",");
function switchThemeButtonState() {
if (themeChoices.style.display === "block") {
var rustdoc_version = document.createElement("span");
rustdoc_version.className = "bottom";
var rustdoc_version_code = document.createElement("code");
- rustdoc_version_code.innerText = "/* INSERT RUSTDOC_VERSION HERE */";
+ rustdoc_version_code.innerText = "rustdoc " + getVar("rustdoc-version");
rustdoc_version.appendChild(rustdoc_version_code);
container.appendChild(rustdoc_version);
-// From rust:
-/* global resourcesSuffix */
var darkThemes = ["dark", "ayu"];
window.currentTheme = document.getElementById("themeStyle");
window.mainTheme = document.getElementById("mainThemeStyle");
}
function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
- var fullBasicCss = "rustdoc" + resourcesSuffix + ".css";
- var fullNewTheme = newTheme + resourcesSuffix + ".css";
- var newHref = mainStyleElem.href.replace(fullBasicCss, fullNewTheme);
+ var newHref = mainStyleElem.href.replace(
+ /\/rustdoc([^/]*)\.css/, "/" + newTheme + "$1" + ".css");
// If this new value comes from a system setting or from the previously
// saved theme, no need to save it.
<link rel="stylesheet" type="text/css" {# -#}
href="{{static_root_path | safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
id="mainThemeStyle"> {#- -#}
- {{- style_files | safe -}}
+ {%- for theme in themes -%}
+ <link rel="stylesheet" type="text/css" {# -#}
+ href="{{static_root_path | safe}}{{theme}}{{page.resource_suffix}}.css" {#- -#}
+ {%- if theme == "light" -%}
+ id="themeStyle"
+ {%- else -%}
+ disabled
+ {%- endif -%}
+ >
+ {%- endfor -%}
<script id="default-settings" {# -#}
{% for k, v in layout.default_settings %}
data-{{k}}="{{v}}"
href="{{static_root_path | safe}}favicon{{page.resource_suffix}}.svg"> {#- -#}
{%- endif -%}
{{- layout.external_html.in_header | safe -}}
- <style type="text/css"> {#- -#}
- #crate-search{ {#- -#}
- background-image:url("{{static_root_path | safe}}down-arrow{{page.resource_suffix}}.svg"); {#- -#}
- } {#- -#}
- </style> {#- -#}
</head> {#- -#}
<body class="rustdoc {{page.css_class}}"> {#- -#}
<!--[if lte IE 11]> {#- -#}
<div id="rustdoc-vars" {# -#}
data-root-path="{{page.root_path | safe}}" {# -#}
data-current-crate="{{layout.krate}}" {# -#}
- data-search-index-js="{{page.root_path | safe}}search-index{{page.resource_suffix}}.js" {# -#}
- data-search-js="{{static_root_path | safe}}search{{page.resource_suffix}}.js"> {#- -#}
+ data-themes="{{themes | join(sep=",") }}" {# -#}
+ data-resource-suffix="{{page.resource_suffix}}" {# -#}
+ data-rustdoc-version="{{rustdoc_version}}" {# -#}
+ > {#- -#}
</div>
</body> {#- -#}
</html> {#- -#}
match bound {
TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => {
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
- let trait_ = clean::ResolvedPath { path: trait_ }.into_tcx(tcx);
+ let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
GenericBound::TraitBound {
trait_,
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
impl FromWithTcx<clean::Type> for Type {
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
- use clean::Type::*;
+ use clean::Type::{
+ Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive,
+ QPath, RawPointer, Slice, Tuple,
+ };
+
match ty {
- ResolvedPath { path } => Type::ResolvedPath {
+ clean::Type::Path { path } => Type::ResolvedPath {
name: path.whole_name(),
id: from_item_id(path.def_id().into()),
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
},
QPath { name, self_type, trait_, .. } => {
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
- let trait_ = ResolvedPath { path: trait_ }.into_tcx(tcx);
+ let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
Type::QualifiedPath {
name: name.to_string(),
self_type: Box::new((*self_type).into_tcx(tcx)),
let provided_trait_methods = impl_.provided_trait_methods(tcx);
let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
- let trait_ = trait_.map(|path| clean::ResolvedPath { path }.into_tcx(tcx));
+ let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
// FIXME: use something like ImplKind in JSON?
let (synthetic, blanket_impl) = match kind {
clean::ImplKind::Normal => (false, None),
#![feature(type_ascription)]
#![feature(iter_intersperse)]
#![recursion_limit = "256"]
+#![feature(unwrap_infallible)]
#![warn(rustc::internal)]
#[macro_use]
.map_err(|err| format!("{}: {}", options.input.display(), err))?;
let mut opts = TestOptions::default();
opts.no_crate_inject = true;
- opts.display_doctest_warnings = options.display_doctest_warnings;
let mut collector = Collector::new(
Symbol::intern(&options.input.display().to_string()),
options.clone(),
find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None);
- crate::doctest::run_tests(
- options.test_args,
- options.nocapture,
- options.display_doctest_warnings,
- collector.tests,
- );
+ crate::doctest::run_tests(options.test_args, options.nocapture, collector.tests);
Ok(())
}
hir::ExprKind::Call(f, _) => {
let types = tcx.typeck(ex.hir_id.owner);
- match types.node_type_opt(f.hir_id) {
- Some(ty) => (ty, ex.span),
- None => {
- return;
- }
+ if let Some(ty) = types.node_type_opt(f.hir_id) {
+ (ty, ex.span)
+ } else {
+ trace!("node_type_opt({}) = None", f.hir_id);
+ return;
}
}
hir::ExprKind::MethodCall(_, _, _, span) => {
let types = tcx.typeck(ex.hir_id.owner);
- let def_id = types.type_dependent_def_id(ex.hir_id).unwrap();
+ let def_id = if let Some(def_id) = types.type_dependent_def_id(ex.hir_id) {
+ def_id
+ } else {
+ trace!("type_dependent_def_id({}) = None", ex.hir_id);
+ return;
+ };
(tcx.type_of(def_id), span)
}
_ => {
if let Some(local_def_id) = def_id.as_local() {
if self.cx.tcx.has_attr(def_id, sym::macro_export) {
if inserted.insert(def_id) {
- let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_def_id);
- let item = self.cx.tcx.hir().expect_item(hir_id);
+ let item = self.cx.tcx.hir().expect_item(local_def_id);
top_level_module.items.push((item, None));
}
}
-// pretty-printers are not loaded
+// ignore-windows-gnu: pretty-printers are not loaded
// compile-flags:-g
// min-gdb-version: 8.1
# needs-profiler-support
+# Rust coverage maps support LLVM Coverage Mapping Format versions 5 and 6,
+# corresponding with LLVM versions 12 and 13, respectively.
+# When upgrading LLVM versions, consider whether to enforce a minimum LLVM
+# version during testing, with an additional directive at the top of this file
+# that sets, for example: `min-llvm-version: 12.0`
+
-include ../coverage/coverage_tools.mk
BASEDIR=../coverage-llvmir
# needs-profiler-support
# ignore-windows-gnu
+# Rust coverage maps support LLVM Coverage Mapping Format versions 5 and 6,
+# corresponding with LLVM versions 12 and 13, respectively.
+# When upgrading LLVM versions, consider whether to enforce a minimum LLVM
+# version during testing, with an additional directive at the top of this file
+# that sets, for example: `min-llvm-version: 12.0`
+
# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
# properly. Since we only have GCC on the CI ignore the test for now.
"$(LLVM_BIN_DIR)"/llvm-cov show \
$(DEBUG_FLAG) \
$(LLVM_COV_IGNORE_FILES) \
+ --compilation-dir=. \
--Xdemangler="$(RUST_DEMANGLER)" \
--show-line-counts-or-regions \
--instr-profile="$(TMPDIR)"/$@.profdata \
-// This test is to ensure that the anchors (`§`) have the expected color.
+// This test is to ensure that the anchors (`§`) have the expected color and position.
goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
show-text: true
// Same thing with the impl block title.
move-cursor-to: "#impl"
assert-css: ("#impl a.anchor", {"color": "rgb(0, 0, 0)"})
+
+// Now we check the positions: only the first heading of the top doc comment should
+// have a different position.
+move-cursor-to: ".top-doc .docblock .section-header:first-child"
+assert-css: (
+ ".top-doc .docblock .section-header:first-child > a::before",
+ {"left": "-10px", "padding-right": "10px"}
+)
+// We also check that the heading itself has a different indent.
+assert-css: (".top-doc .docblock .section-header:first-child", {"margin-left": "15px"})
+
+move-cursor-to: ".top-doc .docblock .section-header:not(:first-child)"
+assert-css: (
+ ".top-doc .docblock .section-header:not(:first-child) > a::before",
+ {"left": "-25px", "padding-right": "10px"}
+)
+assert-css: (".top-doc .docblock .section-header:not(:first-child)", {"margin-left": "0px"})
+
+// Now let's check some other docblock headings...
+// First the impl block docs.
+move-cursor-to: "#title-for-struct-impl-doc"
+assert-css: (
+ "#title-for-struct-impl-doc > a::before",
+ {"left": "-25px", "padding-right": "10px"}
+)
+assert-css: ("#title-for-struct-impl-doc", {"margin-left": "0px"})
+// Now a method docs.
+move-cursor-to: "#title-for-struct-impl-item-doc"
+assert-css: (
+ "#title-for-struct-impl-item-doc > a::before",
+ {"left": "-25px", "padding-right": "10px"}
+)
+assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
+
+// Finally, we want to ensure that if the first element of the doc block isn't a heading,
+// if there is a heading afterwards, it won't have the indent.
+goto: file://|DOC_PATH|/test_docs/enum.WhoLetTheDogOut.html
+
+move-cursor-to: ".top-doc .docblock .section-header"
+assert-css: (
+ ".top-doc .docblock .section-header > a::before",
+ {"left": "-25px", "padding-right": "10px"}
+)
+assert-css: (".top-doc .docblock .section-header", {"margin-left": "0px"})
}
/// Just a normal enum.
+///
+/// # title!
#[doc(alias = "ThisIsAnAlias")]
pub enum WhoLetTheDogOut {
/// Woof!
+// Test that `--show-output` has an effect and `allow(unused)` can be overriden.
+
// check-pass
-// compile-flags:-Zunstable-options --display-doctest-warnings --test
+// edition:2018
+// compile-flags:--test --test-args=--show-output
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
/// ```
+/// #![warn(unused)]
/// let x = 12;
+///
+/// fn foo(x: &std::fmt::Display) {}
/// ```
pub fn foo() {}
running 1 test
-test $DIR/display-output.rs - foo (line 6) ... ok
+test $DIR/display-output.rs - foo (line 9) ... ok
successes:
----- $DIR/display-output.rs - foo (line 6) stdout ----
+---- $DIR/display-output.rs - foo (line 9) stdout ----
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/display-output.rs:13:12
+ |
+LL | fn foo(x: &std::fmt::Display) {}
+ | ^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn std::fmt::Display`
+ |
+ = note: `#[warn(bare_trait_objects)]` on by default
+ = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+
warning: unused variable: `x`
- --> $DIR/display-output.rs:7:5
+ --> $DIR/display-output.rs:11:5
|
LL | let x = 12;
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
- = note: `#[warn(unused_variables)]` on by default
+note: the lint level is defined here
+ --> $DIR/display-output.rs:9:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
+
+warning: unused variable: `x`
+ --> $DIR/display-output.rs:13:8
+ |
+LL | fn foo(x: &std::fmt::Display) {}
+ | ^ help: if this is intentional, prefix it with an underscore: `_x`
+
+warning: function is never used: `foo`
+ --> $DIR/display-output.rs:13:4
+ |
+LL | fn foo(x: &std::fmt::Display) {}
+ | ^^^
+ |
+note: the lint level is defined here
+ --> $DIR/display-output.rs:9:9
+ |
+LL | #![warn(unused)]
+ | ^^^^^^
+ = note: `#[warn(dead_code)]` implied by `#[warn(unused)]`
-warning: 1 warning emitted
+warning: 4 warnings emitted
successes:
- $DIR/display-output.rs - foo (line 6)
+ $DIR/display-output.rs - foo (line 9)
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
--- /dev/null
+// compile-flags: -Z unstable-options --scrape-examples-output-path {{build-base}}/t.calls --scrape-examples-target-crate foobar
+// check-pass
+#![no_std]
+use core as _;
--- /dev/null
+#![feature(doc_notable_trait)]
+
+#[doc(notable_trait)]
+pub trait SomeTrait {}
+
+pub struct SomeStruct;
+pub struct OtherStruct;
+impl SomeTrait for &[SomeStruct] {}
+
+// @has doc_notable_trait_slice/fn.bare_fn_matches.html
+// @has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+pub fn bare_fn_matches() -> &'static [SomeStruct] {
+ &[]
+}
+
+// @has doc_notable_trait_slice/fn.bare_fn_no_matches.html
+// @!has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
+pub fn bare_fn_no_matches() -> &'static [OtherStruct] {
+ &[]
+}
// @has static_root_path/struct.SomeStruct.html
// @matches - '"/cache/main\.js"'
// @!matches - '"\.\./main\.js"'
-// @matches - '"\.\./search-index\.js"'
+// @matches - 'data-root-path="\.\./"'
// @!matches - '"/cache/search-index\.js"'
pub struct SomeStruct;
extern crate rustc_lint;
#[macro_use]
extern crate rustc_session;
-extern crate rustc_span;
extern crate rustc_ast;
+extern crate rustc_span;
use rustc_ast_pretty::pprust;
use rustc_driver::plugin::Registry;
) {
let item = match cx.tcx.hir().get(id) {
Node::Item(item) => item,
- _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id)),
+ _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id).expect_owner()),
};
let allowed = |attr| pprust::attribute_to_string(attr).contains("allowed_attr");
--- /dev/null
+trait NotFoo {}
+
+pub trait Foo: NotFoo {
+ type OnlyFoo;
+}
+
+pub trait Service {
+ type AssocType;
+}
+
+pub trait ThriftService<Bug: NotFoo>:
+//~^ ERROR the trait bound `Bug: Foo` is not satisfied
+//~| ERROR the trait bound `Bug: Foo` is not satisfied
+ Service<AssocType = <Bug as Foo>::OnlyFoo>
+{
+ fn get_service(
+ //~^ ERROR the trait bound `Bug: Foo` is not satisfied
+ //~| ERROR the trait bound `Bug: Foo` is not satisfied
+ &self,
+ ) -> Self::AssocType;
+}
+
+fn with_factory<H>(factory: dyn ThriftService<()>) {}
+//~^ ERROR the trait bound `(): Foo` is not satisfied
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:11:1
+ |
+LL | / pub trait ThriftService<Bug: NotFoo>:
+LL | |
+LL | |
+LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
+... |
+LL | | ) -> Self::AssocType;
+LL | | }
+ | |_^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:11:1
+ |
+LL | / pub trait ThriftService<Bug: NotFoo>:
+LL | |
+LL | |
+LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
+... |
+LL | | ) -> Self::AssocType;
+LL | | }
+ | |_^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:16:5
+ |
+LL | / fn get_service(
+LL | |
+LL | |
+LL | | &self,
+LL | | ) -> Self::AssocType;
+ | |_________________________^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `Bug: Foo` is not satisfied
+ --> $DIR/issue-59324.rs:16:8
+ |
+LL | fn get_service(
+ | ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+ |
+help: consider further restricting this bound
+ |
+LL | pub trait ThriftService<Bug: NotFoo + Foo>:
+ | +++++
+
+error[E0277]: the trait bound `(): Foo` is not satisfied
+ --> $DIR/issue-59324.rs:23:29
+ |
+LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
+ | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+
+#![allow(dead_code)]
+
+trait ParseError {
+ type StreamError;
+}
+
+impl<T> ParseError for T {
+ type StreamError = ();
+}
+
+trait Stream {
+ type Item;
+ type Error: ParseError;
+}
+
+trait Parser
+where
+ <Self as Parser>::PartialState: Default,
+{
+ type PartialState;
+ fn parse_mode(_: &Self, _: Self::PartialState) {
+ loop {}
+ }
+}
+
+impl Stream for () {
+ type Item = ();
+ type Error = ();
+}
+
+impl Parser for () {
+ type PartialState = ();
+}
+
+struct AndThen<A, B>(core::marker::PhantomData<(A, B)>);
+
+impl<A, B> Parser for AndThen<A, B>
+where
+ A: Stream,
+ B: Into<<A::Error as ParseError>::StreamError>,
+{
+ type PartialState = ();
+}
+
+fn expr<A>() -> impl Parser
+where
+ A: Stream<Error = <A as Stream>::Item>,
+{
+ AndThen::<A, ()>(core::marker::PhantomData)
+}
+
+fn parse_mode_impl<A>()
+where
+ <A as Stream>::Error: ParseError,
+ A: Stream<Error = <A as Stream>::Item>,
+{
+ Parser::parse_mode(&expr::<A>(), Default::default())
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+pub trait Foo {
+ type Bar;
+}
+
+pub trait Broken {
+ type Assoc;
+ fn broken(&self) where Self::Assoc: Foo;
+}
+
+impl<T> Broken for T {
+ type Assoc = ();
+ fn broken(&self) where Self::Assoc: Foo {
+ let _x: <Self::Assoc as Foo>::Bar;
+ }
+}
+
+fn main() {
+ let _m: &dyn Broken<Assoc=()> = &();
+}
--- /dev/null
+// check-pass
+
+use std::borrow::Cow;
+
+enum _Recursive<'a>
+where
+ Self: ToOwned<Owned=Box<Self>>
+{
+ Variant(MyCow<'a, _Recursive<'a>>),
+}
+
+pub struct Wrapper<T>(T);
+
+pub struct MyCow<'a, T: ToOwned<Owned=Box<T>> + 'a>(Wrapper<Cow<'a, T>>);
+
+fn main() {}
--- /dev/null
+// check-pass
+
+mod convenience_operators {
+ use crate::{Op, Relation};
+ use std::ops::AddAssign;
+ use std::ops::Mul;
+
+ impl<C: Op> Relation<C> {
+ pub fn map<F: Fn(C::D) -> D2 + 'static, D2: 'static>(
+ self,
+ f: F,
+ ) -> Relation<impl Op<D = D2, R = C::R>> {
+ self.map_dr(move |x, r| (f(x), r))
+ }
+ }
+
+ impl<K: 'static, V: 'static, C: Op<D = (K, V)>> Relation<C> {
+ pub fn semijoin<C2: Op<D = K, R = R2>, R2, R3: AddAssign<R3>>(
+ self,
+ other: Relation<C2>,
+ ) -> Relation<impl Op<D = C::D, R = R3>>
+ where
+ C::R: Mul<R2, Output = R3>,
+ {
+ self.join(other.map(|x| (x, ()))).map(|(k, x, ())| (k, x))
+ }
+ }
+}
+
+mod core {
+ mod operator {
+ mod join {
+ use super::Op;
+ use crate::core::Relation;
+ use std::ops::{AddAssign, Mul};
+ struct Join<LC, RC> {
+ _left: LC,
+ _right: RC,
+ }
+ impl<
+ LC: Op<D = (K, LD), R = LR>,
+ RC: Op<D = (K, RD), R = RR>,
+ K: 'static,
+ LD: 'static,
+ LR: AddAssign<LR> + Mul<RR, Output = OR>,
+ RD: 'static,
+ RR: AddAssign<RR>,
+ OR: AddAssign<OR>,
+ > Op for Join<LC, RC>
+ {
+ type D = (K, LD, RD);
+ type R = OR;
+ }
+ impl<K: 'static, D: 'static, C: Op<D = (K, D)>> Relation<C> {
+ pub fn join<C2: Op<D = (K, D2)>, D2: 'static, OR: AddAssign<OR>>(
+ self,
+ other: Relation<C2>,
+ ) -> Relation<impl Op<D = (K, D, D2), R = OR>>
+ where
+ C::R: Mul<C2::R, Output = OR>,
+ {
+ Relation {
+ inner: Join {
+ _left: self.inner,
+ _right: other.inner,
+ },
+ }
+ }
+ }
+ }
+ mod map {
+ use super::Op;
+ use crate::core::Relation;
+ use std::ops::AddAssign;
+ struct Map<C, MF> {
+ _inner: C,
+ _op: MF,
+ }
+ impl<
+ D1,
+ R1,
+ D2: 'static,
+ R2: AddAssign<R2>,
+ C: Op<D = D1, R = R1>,
+ MF: Fn(D1, R1) -> (D2, R2),
+ > Op for Map<C, MF>
+ {
+ type D = D2;
+ type R = R2;
+ }
+ impl<C: Op> Relation<C> {
+ pub fn map_dr<F: Fn(C::D, C::R) -> (D2, R2), D2: 'static, R2: AddAssign<R2>>(
+ self,
+ f: F,
+ ) -> Relation<impl Op<D = D2, R = R2>> {
+ Relation {
+ inner: Map {
+ _inner: self.inner,
+ _op: f,
+ },
+ }
+ }
+ }
+ }
+ use std::ops::AddAssign;
+ pub trait Op {
+ type D: 'static;
+ type R: AddAssign<Self::R>;
+ }
+ }
+ pub use self::operator::Op;
+ #[derive(Clone)]
+ pub struct Relation<C> {
+ inner: C,
+ }
+}
+
+use self::core::Op;
+pub use self::core::Relation;
+
+fn main() {}
--- /dev/null
+#![feature(rustc_attrs)]
+
+use std::borrow::Cow;
+
+#[rustc_layout(debug)]
+type Edges<'a, E> = Cow<'a, [E]>;
+//~^ ERROR layout error: NormalizationFailure
+
+fn main() {}
--- /dev/null
+error: layout error: NormalizationFailure(<[E] as std::borrow::ToOwned>::Owned, Type(<[E] as std::borrow::ToOwned>::Owned))
+ --> $DIR/issue-85103.rs:6:1
+ |
+LL | type Edges<'a, E> = Cow<'a, [E]>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub trait Trait{
+ type R;
+ fn func(self)->Self::R;
+}
+
+pub struct TraitImpl<const N:usize>(pub i32);
+
+impl<const N:usize> Trait for TraitImpl<N>
+where [();N/2]:,
+{
+ type R = Self;
+ fn func(self)->Self::R {
+ self
+ }
+}
+
+fn sample<P,Convert>(p:P,f:Convert) -> i32
+where
+ P:Trait,Convert:Fn(P::R)->i32
+{
+ f(p.func())
+}
+
+fn main() {
+ let t = TraitImpl::<10>(4);
+ sample(t,|x|x.0);
+}
--- /dev/null
+// check-pass
+
+#![feature(extern_types)]
+#![allow(dead_code)]
+
+extern {
+ type Extern;
+}
+
+trait Trait {
+ type Type;
+}
+
+#[inline]
+fn f<'a>(_: <&'a Extern as Trait>::Type) where &'a Extern: Trait {}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+struct Struct;
+
+trait Trait {
+ type Type;
+}
+
+enum Enum<'a> where &'a Struct: Trait {
+ Variant(<&'a Struct as Trait>::Type)
+}
+
+fn main() {}
|
LL | println!("{}", i);
| ^ use of possibly-uninitialized `i`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{}", i);
| ^ use of possibly-uninitialized `i`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{}", v);
| ^ use of possibly-uninitialized `v`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0381]: borrow of possibly-uninitialized variable: `x`
--> $DIR/issue-24267-flow-exit.rs:18:20
|
LL | println!("{}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:46
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:17:46
|
LL | pub fn e(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:50
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:28:50
|
LL | pub fn ee(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:40:14
|
LL | pub fn capture_assign_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^^^ cannot assign
error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:47:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:45:14
|
LL | pub fn capture_assign_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^^ cannot assign
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:50:14
|
LL | pub fn capture_reborrow_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:57:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:14
|
LL | pub fn capture_reborrow_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:46
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:17:46
|
LL | pub fn e(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:50
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:28:50
|
LL | pub fn ee(x: &'static mut isize) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:40:14
|
LL | pub fn capture_assign_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^^^ cannot assign
error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:47:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:45:14
|
LL | pub fn capture_assign_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^^ cannot assign
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:52:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:50:14
|
LL | pub fn capture_reborrow_whole(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
| ^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable
- --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:57:14
+ --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:55:14
|
LL | pub fn capture_reborrow_part(x: (i32,)) {
| - help: consider changing this to be mutable: `mut x`
// looks at some parent.
// revisions: migrate nll
+//[nll]compile-flags: -Z borrowck=mir
// Since we are testing nll (and migration) explicitly as a separate
// revisions, don't worry about the --compare-mode=nll on this test.
// ignore-compare-mode-nll
-//[nll]compile-flags: -Z borrowck=mir
-
-
// transcribed from borrowck-closures-unique.rs
mod borrowck_closures_unique {
pub fn e(x: &'static mut isize) {
+++ /dev/null
-error[E0506]: cannot assign to `greeting` because it is borrowed
- --> $DIR/issue-58776-borrowck-scans-children.rs:11:5
- |
-LL | let res = (|| (|| &greeting)())();
- | -- -------- borrow occurs due to use in closure
- | |
- | borrow of `greeting` occurs here
-LL |
-LL | greeting = "DEALLOCATED".to_string();
- | ^^^^^^^^ assignment to borrowed `greeting` occurs here
-...
-LL | println!("thread result: {:?}", res);
- | --- borrow later used here
-
-error[E0505]: cannot move out of `greeting` because it is borrowed
- --> $DIR/issue-58776-borrowck-scans-children.rs:14:10
- |
-LL | let res = (|| (|| &greeting)())();
- | -- -------- borrow occurs due to use in closure
- | |
- | borrow of `greeting` occurs here
-...
-LL | drop(greeting);
- | ^^^^^^^^ move out of `greeting` occurs here
-...
-LL | println!("thread result: {:?}", res);
- | --- borrow later used here
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0505, E0506.
-For more information about an error, try `rustc --explain E0505`.
...
LL | c();
| - mutable borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable
--> $DIR/arrays.rs:73:24
LL |
LL | c();
| - mutable borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0506]: cannot assign to `e.0.0.m.x` because it is borrowed
--> $DIR/box.rs:55:5
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: 1 warning emitted
LL |
LL | c();
| - mutable borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
error: generic parameters may not be used in const operations
- --> $DIR/issue-72787.rs:12:17
+ --> $DIR/issue-72787.rs:11:17
|
LL | Condition<{ LHS <= RHS }>: True
| ^^^ cannot perform const operation using `LHS`
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-72787.rs:12:24
+ --> $DIR/issue-72787.rs:11:24
|
LL | Condition<{ LHS <= RHS }>: True
| ^^^ cannot perform const operation using `RHS`
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-72787.rs:26:25
+ --> $DIR/issue-72787.rs:25:25
|
LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
| ^ cannot perform const operation using `I`
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
error: generic parameters may not be used in const operations
- --> $DIR/issue-72787.rs:26:36
+ --> $DIR/issue-72787.rs:25:36
|
LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
| ^ cannot perform const operation using `J`
= help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
error[E0283]: type annotations needed
- --> $DIR/issue-72787.rs:10:38
- |
-LL | impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
- | ^^^^ cannot infer type for struct `IsLessOrEqual<LHS, RHS>`
- |
- = note: cannot satisfy `IsLessOrEqual<LHS, RHS>: True`
-
-error[E0283]: type annotations needed
- --> $DIR/issue-72787.rs:22:26
+ --> $DIR/issue-72787.rs:21:26
|
LL | IsLessOrEqual<I, 8>: True,
| ^^^^ cannot infer type for struct `IsLessOrEqual<I, 8_u32>`
= note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
error[E0283]: type annotations needed
- --> $DIR/issue-72787.rs:22:26
+ --> $DIR/issue-72787.rs:21:26
|
LL | IsLessOrEqual<I, 8>: True,
| ^^^^ cannot infer type for struct `IsLessOrEqual<I, 8_u32>`
|
= note: cannot satisfy `IsLessOrEqual<I, 8_u32>: True`
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0283`.
pub trait True {}
impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
-//[min]~^ ERROR type annotations needed
Condition<{ LHS <= RHS }>: True
//[min]~^ Error generic parameters may not be used in const operations
//[min]~| Error generic parameters may not be used in const operations
--- /dev/null
+// error-pattern: any use of this value will cause an error
+
+#![feature(never_type)]
+#![feature(const_maybe_uninit_assume_init, const_assert_type2)]
+#![feature(core_intrinsics)]
+
+use std::intrinsics;
+
+#[allow(invalid_value)]
+fn main() {
+ use std::mem::MaybeUninit;
+
+ const _BAD1: () = unsafe {
+ MaybeUninit::<!>::uninit().assume_init();
+ };
+ const _BAD2: () = unsafe {
+ intrinsics::assert_uninit_valid::<bool>();
+ };
+ const _BAD3: () = unsafe {
+ intrinsics::assert_zero_valid::<&'static i32>();
+ };
+}
--- /dev/null
+error: any use of this value will cause an error
+ --> $DIR/assert-type-intrinsics.rs:14:9
+ |
+LL | / const _BAD1: () = unsafe {
+LL | | MaybeUninit::<!>::uninit().assume_init();
+ | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
+LL | | };
+ | |______-
+ |
+ = note: `#[deny(const_err)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: any use of this value will cause an error
+ --> $DIR/assert-type-intrinsics.rs:17:9
+ |
+LL | / const _BAD2: () = unsafe {
+LL | | intrinsics::assert_uninit_valid::<bool>();
+ | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
+LL | | };
+ | |______-
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: any use of this value will cause an error
+ --> $DIR/assert-type-intrinsics.rs:20:9
+ |
+LL | / const _BAD3: () = unsafe {
+LL | | intrinsics::assert_zero_valid::<&'static i32>();
+ | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid
+LL | | };
+ | |______-
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: aborting due to 3 previous errors
+
+++ /dev/null
-// error-pattern: any use of this value will cause an error
-
-#![feature(never_type)]
-#![feature(const_maybe_uninit_assume_init)]
-
-#[allow(invalid_value)]
-fn main() {
- use std::mem::MaybeUninit;
-
- const _BAD: () = unsafe {
- MaybeUninit::<!>::uninit().assume_init();
- };
-}
+++ /dev/null
-error: any use of this value will cause an error
- --> $DIR/assume-type-intrinsics.rs:11:9
- |
-LL | / const _BAD: () = unsafe {
-LL | | MaybeUninit::<!>::uninit().assume_init();
- | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
-LL | | };
- | |______-
- |
- = note: `#[deny(const_err)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-
-error: aborting due to previous error
-
-static a: &'static str = "foo";
-static b: *const u8 = a as *const u8; //~ ERROR casting
-static c: *const u8 = &a as *const u8; //~ ERROR casting
+const a: &str = "foo";
+const b: *const u8 = a as *const u8; //~ ERROR casting
+const c: *const u8 = &a as *const u8; //~ ERROR casting
fn main() {
}
error[E0606]: casting `&'static str` as `*const u8` is invalid
- --> $DIR/const-cast-different-types.rs:2:23
+ --> $DIR/const-cast-different-types.rs:2:22
|
-LL | static b: *const u8 = a as *const u8;
- | ^^^^^^^^^^^^^^
+LL | const b: *const u8 = a as *const u8;
+ | ^^^^^^^^^^^^^^
error[E0606]: casting `&&'static str` as `*const u8` is invalid
- --> $DIR/const-cast-different-types.rs:3:23
+ --> $DIR/const-cast-different-types.rs:3:22
|
-LL | static c: *const u8 = &a as *const u8;
- | ^^^^^^^^^^^^^^^
+LL | const c: *const u8 = &a as *const u8;
+ | ^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
-static a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8];
-static b: *const i8 = &a as *const i8; //~ ERROR mismatched types
+const a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8];
+const b: *const i8 = &a as *const i8; //~ ERROR mismatched types
fn main() {
}
error[E0308]: mismatched types
- --> $DIR/const-cast-wrong-type.rs:2:23
+ --> $DIR/const-cast-wrong-type.rs:2:22
|
-LL | static b: *const i8 = &a as *const i8;
- | ^^^^^^^^^^^^^^^ expected `u8`, found `i8`
+LL | const b: *const i8 = &a as *const i8;
+ | ^^^^^^^^^^^^^^^ expected `u8`, found `i8`
error: aborting due to previous error
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error; 2 warnings emitted
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0080]: evaluation of constant value failed
--> $DIR/issue-43197.rs:16:26
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors; 4 warnings emitted
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
-// ignore-compare-mode-nll
-
// Check that E0161 is a hard error in all possible configurations that might
// affect it.
//[zflagsul] check-pass
//[editionul] check-pass
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
#![allow(incomplete_features)]
#![cfg_attr(nll, feature(nll))]
#![cfg_attr(nllul, feature(nll))]
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
- --> $DIR/E0161.rs:29:5
+ --> $DIR/E0161.rs:32:5
|
LL | x.f();
| ^^^^^
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5
+ |
+LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | s
+ | ^ returning this value requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: aborting due to previous error
+
--- /dev/null
+// check-fail
+// See issue #91068. Types in the substs of an associated type can't be implied
+// to be WF, since they don't actually have to be constructed.
+
+trait Trait {
+ type Type;
+}
+
+impl<T> Trait for T {
+ type Type = ();
+}
+
+fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
+ s //~ ERROR lifetime mismatch [E0623]
+}
+
+fn main() {
+ let x = String::from("Hello World!");
+ let y = f(&x, ());
+ drop(x);
+ println!("{}", y);
+}
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5
+ |
+LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
+ | ------- ----------
+ | |
+ | these two types are declared with different lifetimes...
+LL | s
+ | ^ ...but data from `s` flows here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
| ^ second borrow occurs here
LL | Pin::new(&mut b).resume(());
| ------ first borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
--- /dev/null
+fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
+//~^ ERROR equality constraints are not yet supported in `where` clauses
+ panic!()
+}
+fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
+//~^ ERROR equality constraints are not yet supported in `where` clauses
+ panic!()
+}
+fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
+//~^ ERROR equality constraints are not yet supported in `where` clauses
+//~| ERROR failed to resolve: use of undeclared type `I`
+ panic!()
+}
+
+fn main() {}
--- /dev/null
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/equality-bound.rs:1:51
+ |
+LL | fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
+ | ^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
+ |
+LL - fn sum<I: Iterator<Item = ()>>(i: I) -> i32 where I::Item = i32 {
+LL + fn sum<I: Iterator<Item = (), Item = i32>>(i: I) -> i32 where {
+ |
+
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/equality-bound.rs:5:41
+ |
+LL | fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
+ | ^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax
+ |
+LL - fn sum2<I: Iterator>(i: I) -> i32 where I::Item = i32 {
+LL + fn sum2<I: Iterator<Item = i32>>(i: I) -> i32 where {
+ |
+
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/equality-bound.rs:9:41
+ |
+LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
+ | ^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+
+error[E0433]: failed to resolve: use of undeclared type `I`
+ --> $DIR/equality-bound.rs:9:41
+ |
+LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 {
+ | ^ use of undeclared type `I`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
+++ /dev/null
-// Checks that we properly add implied bounds from unnormalized projections in
-// inputs when typechecking functions.
-
-// check-pass
-
-#![feature(generic_associated_types)]
-
-trait MyTrait {
- type Assoc<'a, 'b> where 'b: 'a;
- fn do_sth(arg: Self::Assoc<'_, '_>);
-}
-
-struct A;
-struct B;
-struct C;
-
-impl MyTrait for A {
- type Assoc<'a, 'b> where 'b: 'a = u32;
- fn do_sth(_: u32) {}
-}
-impl MyTrait for B {
- type Assoc<'a, 'b> where 'b: 'a = u32;
- fn do_sth(_: Self::Assoc<'_, '_>) {}
-}
-impl MyTrait for C {
- type Assoc<'a, 'b> where 'b: 'a = u32;
- fn do_sth(_: Self::Assoc<'static, 'static>) {}
-}
-
-fn main () {}
struct E<B>(B);
-impl<B: Add> Add for E<B> where B: Add<Output = B> {
+impl<B: Add> Add for E<B> where B: Add<Output = B>, B: Add<Output = B> {
+ //~^ ERROR equality constraints are not yet supported in `where` clauses
type Output = Self;
fn add(self, rhs: Self) -> Self {
- Self(self.0 + rhs.0)
+ Self(self.0 + rhs.0) //~ ERROR mismatched types
}
}
struct E<B>(B);
-impl<B: Add> Add for E<B> where B: Add<Output = B> {
+impl<B: Add> Add for E<B> where <B as Add>::Output = B {
+ //~^ ERROR equality constraints are not yet supported in `where` clauses
type Output = Self;
fn add(self, rhs: Self) -> Self {
- Self(self.0 + rhs.0)
+ Self(self.0 + rhs.0) //~ ERROR mismatched types
}
}
+error: equality constraints are not yet supported in `where` clauses
+ --> $DIR/missing-bounds.rs:37:33
+ |
+LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
+ | ^^^^^^^^^^^^^^^^^^^^^^ not supported
+ |
+ = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+help: if `Output` is an associated type you're trying to set, use the associated type binding syntax
+ |
+LL | impl<B: Add> Add for E<B> where B: Add<Output = B> {
+ | ~~~~~~~~~~~~~~~~~~
+
error[E0308]: mismatched types
--> $DIR/missing-bounds.rs:11:11
|
LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
| +++++++++++++++++++++++++++
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+ --> $DIR/missing-bounds.rs:42:14
+ |
+LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
+ | - this type parameter
+...
+LL | Self(self.0 + rhs.0)
+ | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type
+ |
+ = note: expected type parameter `B`
+ found associated type `<B as Add>::Output`
+help: consider further restricting type parameter `B`
+ |
+LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B, B: Add<Output = B> {
+ | ++++++++++++++++++++
+
+error: aborting due to 5 previous errors
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+// Regression test for #88586: a higher-ranked outlives bound on Self in a trait
+// definition caused an ICE when debug_assertions were enabled.
+//
+// FIXME: The error output in the absence of the ICE is unhelpful; this should be improved.
+
+trait A where for<'a> Self: 'a
+//~^ ERROR the parameter type `Self` may not live long enough
+{
+}
+
+fn main() {}
--- /dev/null
+error[E0311]: the parameter type `Self` may not live long enough
+ --> $DIR/issue-88586-hr-self-outlives-in-trait-def.rs:6:1
+ |
+LL | / trait A where for<'a> Self: 'a
+LL | |
+LL | | {
+LL | | }
+ | |_^
+ |
+ = help: consider adding an explicit lifetime bound `Self: 'a`...
+ = note: ...so that the type `Self` will meet its required lifetime bounds...
+note: ...that is required by this bound
+ --> $DIR/issue-88586-hr-self-outlives-in-trait-def.rs:6:29
+ |
+LL | trait A where for<'a> Self: 'a
+ | ^^
+
+error: aborting due to previous error
+
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:52:5
+ --> $DIR/issue-71955.rs:57:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:52:5
+ --> $DIR/issue-71955.rs:57:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:52:5
+ --> $DIR/issue-71955.rs:57:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:52:5
+ --> $DIR/issue-71955.rs:57:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:52:5
+ --> $DIR/issue-71955.rs:57:5
|
LL | foo(bar, "string", |s| s.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
= note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
error: implementation of `Parser` is not general enough
- --> $DIR/issue-71955.rs:58:5
+ --> $DIR/issue-71955.rs:63:5
|
LL | foo(baz, "string", |s| s.0.len() == 5);
| ^^^ implementation of `Parser` is not general enough
error: fatal error triggered by #[rustc_error]
- --> $DIR/issue-71955.rs:42:1
+ --> $DIR/issue-71955.rs:47:1
|
LL | fn main() {
| ^^^^^^^^^
// [nll]compile-flags: -Zborrowck=mir
// check-fail
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
#![feature(rustc_attrs)]
trait Parser<'s> {
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:128:22
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:127:22
|
LL | pub struct Map<S, F> {
| --------------------
| doesn't satisfy `_: StreamExt`
...
LL | let filter = map.filterx(|x: &_| true);
- | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` due to unsatisfied trait bounds
+ | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:141:24
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:140:24
|
LL | pub struct Filter<S, F> {
| -----------------------
| doesn't satisfy `_: StreamExt`
...
LL | let count = filter.countx();
- | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` due to unsatisfied trait bounds
+ | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:128:22
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:127:22
|
LL | pub struct Map<S, F> {
| --------------------
| doesn't satisfy `_: StreamExt`
...
LL | let filter = map.filterx(|x: &_| true);
- | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>` due to unsatisfied trait bounds
+ | ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:127:27: 127:36]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:126:27: 126:36]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>`, but its trait bounds were not satisfied
- --> $DIR/issue-30786.rs:141:24
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>`, but its trait bounds were not satisfied
+ --> $DIR/issue-30786.rs:140:24
|
LL | pub struct Filter<S, F> {
| -----------------------
| doesn't satisfy `_: StreamExt`
...
LL | let count = filter.countx();
- | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>` due to unsatisfied trait bounds
+ | ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied because of the requirements of the implementation of `StreamExt` for `_`:
- `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:140:30: 140:42]>: Stream`
- --> $DIR/issue-30786.rs:106:9
+ `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:139:30: 139:42]>: Stream`
+ --> $DIR/issue-30786.rs:105:9
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| ^^^^^^^^^ ^
// through again.
// revisions: migrate nll
+//[nll]compile-flags: -Z borrowck=mir
// Since we are testing nll (and migration) explicitly as a separate
// revisions, don't worry about the --compare-mode=nll on this test.
// ignore-compare-mode-nll
// ignore-compare-mode-polonius
-//[nll]compile-flags: -Z borrowck=mir
-
pub trait Stream {
type Item;
fn next(self) -> Option<Self::Item>;
#![feature(type_alias_impl_trait)]
type FunType = impl Fn<()>;
-//~^ could not find defining uses
+//~^ ERROR could not find defining uses
static STATIC_FN: FunType = some_fn;
-//~^ mismatched types
+//~^ ERROR mismatched types
fn some_fn() {}
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
- --> $DIR/issue-16538.rs:14:27
+ --> $DIR/issue-16538.rs:15:23
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0277]: `*const usize` cannot be shared between threads safely
- --> $DIR/issue-16538.rs:14:1
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-16538.rs:15:30
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^ use of extern static
|
- = help: the trait `Sync` is not implemented for `*const usize`
- = note: shared static variables must have a type that implements `Sync`
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-16538.rs:14:34
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-16538.rs:15:21
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^ use of extern static
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
|
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0015, E0133, E0277.
+Some errors have detailed explanations: E0015, E0133.
For more information about an error, try `rustc --explain E0015`.
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck
+#![feature(const_raw_ptr_deref)]
mod Y {
pub type X = usize;
extern "C" {
}
}
-static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
-//~^ ERROR `*const usize` cannot be shared between threads safely [E0277]
+static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+//~^ ERROR dereference of raw pointer
//~| ERROR E0015
//~| ERROR use of extern static is unsafe and requires
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-16538.rs:15:22
+ |
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-16538.rs:14:34
+ --> $DIR/issue-16538.rs:15:30
|
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^ use of extern static
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^ use of extern static
|
= note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
- --> $DIR/issue-16538.rs:14:27
- |
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: `*const usize` cannot be shared between threads safely
- --> $DIR/issue-16538.rs:14:1
- |
-LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely
+ --> $DIR/issue-16538.rs:15:23
|
- = help: the trait `Sync` is not implemented for `*const usize`
- = note: shared static variables must have a type that implements `Sync`
+LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0015, E0133, E0277.
+Some errors have detailed explanations: E0015, E0133.
For more information about an error, try `rustc --explain E0015`.
error[E0277]: `Foo` cannot be shared between threads safely
- --> $DIR/issue-17718-static-sync.rs:9:1
+ --> $DIR/issue-17718-static-sync.rs:9:13
|
LL | static BAR: Foo = Foo;
- | ^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be shared between threads safely
+ | ^^^ `Foo` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `Foo`
= note: shared static variables must have a type that implements `Sync`
fn main() {
static foo: dyn Fn() -> u32 = || -> u32 {
//~^ ERROR the size for values of type
+ //~| ERROR cannot be shared between threads safely
0
};
}
|
= help: the trait `Sized` is not implemented for `(dyn Fn() -> u32 + 'static)`
-error: aborting due to previous error
+error[E0277]: `(dyn Fn() -> u32 + 'static)` cannot be shared between threads safely
+ --> $DIR/issue-24446.rs:2:17
+ |
+LL | static foo: dyn Fn() -> u32 = || -> u32 {
+ | ^^^^^^^^^^^^^^^ `(dyn Fn() -> u32 + 'static)` cannot be shared between threads safely
+ |
+ = help: the trait `Sync` is not implemented for `(dyn Fn() -> u32 + 'static)`
+ = note: shared static variables must have a type that implements `Sync`
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
...
LL | println!("{}", s);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
...
LL | };
| - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option<PeekMut<'_, i32>>, ())`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
fn f() { }
-struct S(Box<dyn FnMut()>);
+struct S(Box<dyn FnMut() + Sync>);
pub static C: S = S(f); //~ ERROR mismatched types
fn g() { }
-type T = Box<dyn FnMut()>;
+type T = Box<dyn FnMut() + Sync>;
pub static D: T = g; //~ ERROR mismatched types
fn main() {}
LL | pub static C: S = S(f);
| ^ expected struct `Box`, found fn item
|
- = note: expected struct `Box<(dyn FnMut() + 'static)>`
+ = note: expected struct `Box<(dyn FnMut() + Sync + 'static)>`
found fn item `fn() {f}`
error[E0308]: mismatched types
LL | pub static D: T = g;
| ^ expected struct `Box`, found fn item
|
- = note: expected struct `Box<(dyn FnMut() + 'static)>`
+ = note: expected struct `Box<(dyn FnMut() + Sync + 'static)>`
found fn item `fn() {g}`
error: aborting due to 2 previous errors
// Regression test for issue 7364
static boxed: Box<RefCell<isize>> = box RefCell::new(0);
-//~^ ERROR allocations are not allowed in statics
-//~| ERROR `RefCell<isize>` cannot be shared between threads safely [E0277]
+//~^ ERROR `RefCell<isize>` cannot be shared between threads safely [E0277]
fn main() { }
-error[E0010]: allocations are not allowed in statics
- --> $DIR/issue-7364.rs:6:37
- |
-LL | static boxed: Box<RefCell<isize>> = box RefCell::new(0);
- | ^^^^^^^^^^^^^^^^^^^ allocation not allowed in statics
-
error[E0277]: `RefCell<isize>` cannot be shared between threads safely
- --> $DIR/issue-7364.rs:6:1
+ --> $DIR/issue-7364.rs:6:15
|
LL | static boxed: Box<RefCell<isize>> = box RefCell::new(0);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely
+ | ^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `RefCell<isize>`
= note: required because of the requirements on the impl of `Sync` for `Unique<RefCell<isize>>`
= note: required because it appears within the type `Box<RefCell<isize>>`
= note: shared static variables must have a type that implements `Sync`
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0010, E0277.
-For more information about an error, try `rustc --explain E0010`.
+For more information about this error, try `rustc --explain E0277`.
}
impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
//~^ ERROR cannot find type `VAL` in this scope
-//~| ERROR type annotations needed
+//~| ERROR not all trait items implemented, missing: `VAL`
| |
| help: you might be missing a type parameter: `, VAL`
-error[E0283]: type annotations needed
- --> $DIR/issue-77919.rs:11:12
+error[E0046]: not all trait items implemented, missing: `VAL`
+ --> $DIR/issue-77919.rs:11:1
|
+LL | const VAL: T;
+ | ------------- `VAL` from trait
+...
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
- | ^^^^^^^^^^^^^^ cannot infer type for struct `Multiply<N, M>`
- |
- = note: cannot satisfy `Multiply<N, M>: TypeVal<usize>`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0283, E0412.
-For more information about an error, try `rustc --explain E0283`.
+Some errors have detailed explanations: E0046, E0412.
+For more information about an error, try `rustc --explain E0046`.
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
num == 3
}
+fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {}
+//~^ ERROR: unused doc comment
+
fn main() {}
|
= help: use `//` for a plain comment
+error: unused doc comment
+ --> $DIR/unused-doc-comments-edge-cases.rs:29:27
+ |
+LL | fn doc_comment_on_generic<#[doc = "x"] T>(val: T) {}
+ | ^^^^^^^^^^^^ - rustdoc does not generate documentation for generic parameters
+ |
+ = help: use `//` for a plain comment
+
error[E0308]: mismatched types
--> $DIR/unused-doc-comments-edge-cases.rs:14:9
|
LL | return true;
| ++++++ +
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
Some errors have detailed explanations: E0308, E0658.
For more information about an error, try `rustc --explain E0308`.
| ^ value borrowed here after move
LL | while true { while true { while true { x = y; x.clone(); } } }
| - value moved here, in previous iteration of loop
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error; 3 warnings emitted
LL |
LL | println!("{}", *x);
| ^^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
| ------- value moved here
LL | println!("{}", message);
| ^^^^^^^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | println!("{:?}", x);
| ^ use of possibly-uninitialized `x`
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
LL | });
LL | println!("{}", x);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
--- /dev/null
+// build-pass
+// ignore-pass
+// no-system-llvm
+// revisions: all inline merge1 merge2
+// compile-flags: --crate-type=lib -Cdebuginfo=1 -Copt-level=2
+//
+// Check that remarks can be enabled individually or with "all":
+//
+// [all] compile-flags: -Cremark=all
+// [inline] compile-flags: -Cremark=inline
+//
+// Check that values of -Cremark flag are accumulated:
+//
+// [merge1] compile-flags: -Cremark=all -Cremark=giraffe
+// [merge2] compile-flags: -Cremark=inline -Cremark=giraffe
+//
+// error-pattern: inline: f not inlined into g
+// dont-check-compiler-stderr
+
+#[no_mangle]
+#[inline(never)]
+pub fn f() {
+}
+
+#[no_mangle]
+pub fn g() {
+ f();
+}
// Tests that a suggestion is issued if the user wrote a colon instead of
// a path separator in a match arm.
-enum Foo {
- Bar,
- Baz,
+mod qux {
+ pub enum Foo {
+ Bar,
+ Baz,
+ }
}
+use qux::Foo;
+
fn f() -> Foo { Foo::Bar }
fn g1() {
_ => {}
}
match f() {
- Foo::Bar:Baz => {}
+ qux::Foo:Bar => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
_ => {}
}
match f() {
- Foo:Bar::Baz => {}
+ qux:Foo::Baz => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
_ => {}
}
match f() {
- Foo: Bar::Baz if true => {}
+ qux: Foo::Baz if true => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
_ => {}
}
- if let Bar:Baz = f() {
+ if let Foo:Bar = f() {
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
}
fn g1_neg() {
match f() {
- ref Foo: Bar::Baz => {}
+ ref qux: Foo::Baz => {}
//~^ ERROR: expected one of
+ //~| HELP: maybe write a path separator here
_ => {}
}
}
fn g2_neg() {
match f() {
- mut Foo: Bar::Baz => {}
+ mut qux: Foo::Baz => {}
//~^ ERROR: expected one of
+ //~| HELP: maybe write a path separator here
_ => {}
}
}
Foo:Bar::Baz => {}
//~^ ERROR: expected one of
//~| HELP: maybe write a path separator here
+ //~| ERROR: failed to resolve: `Bar` is a variant, not a module
+ }
+ match myfoo {
+ Foo::Bar => {}
+ Foo:Bar => {}
+ //~^ ERROR: expected one of
+ //~| HELP: maybe write a path separator here
}
}
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:13:12
+ --> $DIR/issue-87086-colon-path-sep.rs:17:12
|
LL | Foo:Bar => {}
| ^
| help: maybe write a path separator here: `::`
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:19:17
+ --> $DIR/issue-87086-colon-path-sep.rs:23:17
|
-LL | Foo::Bar:Baz => {}
+LL | qux::Foo:Bar => {}
| ^
| |
| expected one of 8 possible tokens
| help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:25:12
+ --> $DIR/issue-87086-colon-path-sep.rs:29:12
|
-LL | Foo:Bar::Baz => {}
+LL | qux:Foo::Baz => {}
| ^
| |
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:31:12
+ --> $DIR/issue-87086-colon-path-sep.rs:35:12
|
-LL | Foo: Bar::Baz if true => {}
+LL | qux: Foo::Baz if true => {}
| ^
| |
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:36:15
+ --> $DIR/issue-87086-colon-path-sep.rs:40:15
|
-LL | if let Bar:Baz = f() {
+LL | if let Foo:Bar = f() {
| ^
| |
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
-error: expected one of `=>`, `@`, `if`, or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:44:16
+error: expected one of `@` or `|`, found `:`
+ --> $DIR/issue-87086-colon-path-sep.rs:48:16
|
-LL | ref Foo: Bar::Baz => {}
- | ^ expected one of `=>`, `@`, `if`, or `|`
+LL | ref qux: Foo::Baz => {}
+ | ^
+ | |
+ | expected one of `@` or `|`
+ | help: maybe write a path separator here: `::`
-error: expected one of `=>`, `@`, `if`, or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:52:16
+error: expected one of `@` or `|`, found `:`
+ --> $DIR/issue-87086-colon-path-sep.rs:57:16
|
-LL | mut Foo: Bar::Baz => {}
- | ^ expected one of `=>`, `@`, `if`, or `|`
+LL | mut qux: Foo::Baz => {}
+ | ^
+ | |
+ | expected one of `@` or `|`
+ | help: maybe write a path separator here: `::`
error: expected one of `@` or `|`, found `:`
- --> $DIR/issue-87086-colon-path-sep.rs:62:12
+ --> $DIR/issue-87086-colon-path-sep.rs:68:12
|
LL | Foo:Bar::Baz => {}
| ^
| expected one of `@` or `|`
| help: maybe write a path separator here: `::`
-error: aborting due to 8 previous errors
+error: expected one of `@` or `|`, found `:`
+ --> $DIR/issue-87086-colon-path-sep.rs:75:12
+ |
+LL | Foo:Bar => {}
+ | ^
+ | |
+ | expected one of `@` or `|`
+ | help: maybe write a path separator here: `::`
+
+error[E0433]: failed to resolve: `Bar` is a variant, not a module
+ --> $DIR/issue-87086-colon-path-sep.rs:68:13
+ |
+LL | Foo:Bar::Baz => {}
+ | ^^^ `Bar` is a variant, not a module
+
+error: aborting due to 10 previous errors
+For more information about this error, try `rustc --explain E0433`.
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12
- |
-LL | fn with_assoc<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to previous error
-
error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:12
|
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:15
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:38:15
|
LL | fn with_assoc<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:33:18
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:38:18
|
LL | fn with_assoc<'a,'b>() {
| ^^
error: lifetime may not live long enough
- --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:39:12
+ --> $DIR/regions-assoc-type-in-supertrait-outlives-container.rs:44:12
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
// revisions: migrate nll
//[nll]compile-flags: -Z borrowck=mir
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
#![allow(dead_code)]
pub trait TheTrait {
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:11:12
- |
-LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | let z: Option<&'b &'a usize> = None;
- | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
- |
- = help: consider adding the following bound: `'a: 'b`
-
-error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:17:12
- |
-LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | let y: Paramd<'a> = Paramd { x: a };
-LL | let z: Option<&'b Paramd<'a>> = None;
- | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'b`
- |
- = help: consider adding the following bound: `'a: 'b`
-
-error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:22:12
- |
-LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | let z: Option<&'a &'b usize> = None;
- | ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to 3 previous errors
-
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
+ --> $DIR/regions-free-region-ordering-caller.rs:16:12
|
LL | let z: Option<&'b &'a usize> = None;
| ^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'b` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:10:14
+ --> $DIR/regions-free-region-ordering-caller.rs:15: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 here
- --> $DIR/regions-free-region-ordering-caller.rs:10:10
+ --> $DIR/regions-free-region-ordering-caller.rs:15:10
|
LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
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
+ --> $DIR/regions-free-region-ordering-caller.rs:22:12
|
LL | let z: Option<&'b Paramd<'a>> = None;
| ^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'b` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:15:14
+ --> $DIR/regions-free-region-ordering-caller.rs:20: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 here
- --> $DIR/regions-free-region-ordering-caller.rs:15:10
+ --> $DIR/regions-free-region-ordering-caller.rs:20:10
|
LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
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
+ --> $DIR/regions-free-region-ordering-caller.rs:27:12
|
LL | let z: Option<&'a &'b usize> = None;
| ^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-free-region-ordering-caller.rs:21:10
+ --> $DIR/regions-free-region-ordering-caller.rs:26: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 here
- --> $DIR/regions-free-region-ordering-caller.rs:21:14
+ --> $DIR/regions-free-region-ordering-caller.rs:26:14
|
LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
| ^^
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:11:12
+ --> $DIR/regions-free-region-ordering-caller.rs:16:12
|
LL | fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:17:12
+ --> $DIR/regions-free-region-ordering-caller.rs:22:12
|
LL | fn call3<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'a: 'b`
error: lifetime may not live long enough
- --> $DIR/regions-free-region-ordering-caller.rs:22:12
+ --> $DIR/regions-free-region-ordering-caller.rs:27:12
|
LL | fn call4<'a, 'b>(a: &'a usize, b: &'b usize) {
| -- -- lifetime `'b` defined here
// revisions: migrate nll
//[nll]compile-flags: -Z borrowck=mir
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
struct Paramd<'a> { x: &'a usize }
fn call2<'a, 'b>(a: &'a usize, b: &'b usize) {
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12
- |
-LL | fn with_assoc<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12
- |
-LL | fn with_assoc_sub<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to 2 previous errors
-
error[E0491]: in type `&'a WithHrAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12
|
LL | let _: &'a WithHrAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:27:15
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:32:15
|
LL | fn with_assoc<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:27:18
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:32:18
|
LL | fn with_assoc<'a,'b>() {
| ^^
error[E0491]: in type `&'a WithHrAssocSub<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:55:12
|
LL | let _: &'a WithHrAssocSub<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:46:19
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:51:19
|
LL | fn with_assoc_sub<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container-hrtb.rs:46:22
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:51:22
|
LL | fn with_assoc_sub<'a,'b>() {
| ^^
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:30:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:35:12
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
= help: consider adding the following bound: `'b: 'a`
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-hrtb.rs:50:12
+ --> $DIR/regions-outlives-projection-container-hrtb.rs:55:12
|
LL | fn with_assoc_sub<'a,'b>() {
| -- -- lifetime `'b` defined here
// revisions: migrate nll
//[nll]compile-flags: -Z borrowck=mir
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
#![allow(dead_code)]
pub trait TheTrait<'b> {
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-wc.rs:33:12
- |
-LL | fn with_assoc<'a,'b>() {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-...
-LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'a`
- |
- = help: consider adding the following bound: `'b: 'a`
-
-error: aborting due to previous error
-
error[E0491]: in type `&'a WithAssoc<TheType<'b>>`, reference has a longer lifetime than the data it references
- --> $DIR/regions-outlives-projection-container-wc.rs:33:12
+ --> $DIR/regions-outlives-projection-container-wc.rs:38:12
|
LL | let _: &'a WithAssoc<TheType<'b>> = loop { };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the pointer is valid for the lifetime `'a` as defined here
- --> $DIR/regions-outlives-projection-container-wc.rs:27:15
+ --> $DIR/regions-outlives-projection-container-wc.rs:32:15
|
LL | fn with_assoc<'a,'b>() {
| ^^
note: but the referenced data is only valid for the lifetime `'b` as defined here
- --> $DIR/regions-outlives-projection-container-wc.rs:27:18
+ --> $DIR/regions-outlives-projection-container-wc.rs:32:18
|
LL | fn with_assoc<'a,'b>() {
| ^^
error: lifetime may not live long enough
- --> $DIR/regions-outlives-projection-container-wc.rs:33:12
+ --> $DIR/regions-outlives-projection-container-wc.rs:38:12
|
LL | fn with_assoc<'a,'b>() {
| -- -- lifetime `'b` defined here
// revisions: migrate nll
//[nll]compile-flags: -Z borrowck=mir
+// Since we are testing nll (and migration) explicitly as a separate
+// revisions, don't worry about the --compare-mode=nll on this test.
+
+// ignore-compare-mode-nll
+
#![allow(dead_code)]
pub trait TheTrait {
pub enum NonExhaustiveSingleVariant {
A(bool),
}
+
+#[repr(u8)]
+pub enum FieldLessWithNonExhaustiveVariant {
+ A,
+ B,
+ #[non_exhaustive]
+ C,
+}
+
+impl Default for FieldLessWithNonExhaustiveVariant {
+ fn default() -> Self { Self::A }
+}
--- /dev/null
+// aux-build:enums.rs
+// run-pass
+
+extern crate enums;
+
+use enums::FieldLessWithNonExhaustiveVariant;
+
+fn main() {
+ let e = FieldLessWithNonExhaustiveVariant::default();
+ // FIXME: https://github.com/rust-lang/rust/issues/91161
+ // This `as` cast *should* be an error, since it would fail
+ // if the non-exhaustive variant got fields. But today it
+ // doesn't. The fix for that will update this test to
+ // show an error (and not be run-pass any more).
+ let d = e as u8;
+ assert_eq!(d, 0);
+}
-error[E0277]: `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
- --> $DIR/rfc1623.rs:21:1
- |
-LL | / static SOME_STRUCT: &SomeStruct = &SomeStruct {
-LL | | foo: &Foo { bools: &[false, true] },
-LL | | bar: &Bar { bools: &[true, true] },
-LL | | f: &id,
-LL | |
-LL | | };
- | |__^ `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely
- |
- = help: within `&SomeStruct`, the trait `Sync` is not implemented for `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>`
- = note: required because it appears within the type `&dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>`
-note: required because it appears within the type `SomeStruct`
- --> $DIR/rfc1623.rs:11:8
- |
-LL | struct SomeStruct<'x, 'y, 'z: 'x> {
- | ^^^^^^^^^^
- = note: required because it appears within the type `&SomeStruct`
- = note: shared static variables must have a type that implements `Sync`
-
error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
found type `Fn<(&Foo<'_>,)>`
error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
found type `Fn<(&Foo<'_>,)>`
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
= note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:21:35
+ --> $DIR/rfc1623.rs:25:35
|
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
| ___________________________________^
= note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
-Some errors have detailed explanations: E0277, E0308.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0308`.
f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>,
}
+// Without this, the wf-check will fail early so we'll never see the
+// error in SOME_STRUCT's body.
+unsafe impl<'x, 'y, 'z: 'x> Sync for SomeStruct<'x, 'y, 'z> {}
+
fn id<T>(t: T) -> T {
t
}
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:24:8
+ --> $DIR/rfc1623.rs:28:8
|
LL | f: &id,
| ^^^ implementation of `FnOnce` is not general enough
LL | };
LL | println!("{}", x);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/try-block-maybe-bad-lifetime.rs:40:9
use std::fmt::Debug;
-type Foo = impl Debug;
-//~^ ERROR: could not find defining uses
+type Foo = impl Debug; //~ ERROR could not find defining uses
-static FOO1: Foo = 22_u32;
-//~^ ERROR: mismatched types [E0308]
-const FOO2: Foo = 22_u32;
-//~^ ERROR: mismatched types [E0308]
+static FOO1: Foo = 22_u32; //~ ERROR mismatched types
+const FOO2: Foo = 22_u32; //~ ERROR mismatched types
fn main() {}
error[E0308]: mismatched types
- --> $DIR/static-const-types.rs:11:20
+ --> $DIR/static-const-types.rs:10:20
|
LL | type Foo = impl Debug;
| ---------- the expected opaque type
-...
+LL |
LL | static FOO1: Foo = 22_u32;
| ^^^^^^ expected opaque type, found `u32`
|
found type `u32`
error[E0308]: mismatched types
- --> $DIR/static-const-types.rs:13:19
+ --> $DIR/static-const-types.rs:11:19
|
LL | type Foo = impl Debug;
| ---------- the expected opaque type
| - value moved here
LL | println!("{}", x);
| ^ value borrowed here after move
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
|
LL | fn make_string_bar(mut self) -> Mine{
| ^^^^
+ = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
-Subproject commit 7f08ace4f1305de7f3b1b0e2f765911957226bd4
+Subproject commit 294967c53f0c70d598fc54ca189313c86c576ea7
use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::{get_trait_def_id, is_automatically_derived, is_lint_allowed, match_def_path};
use if_chain::if_chain;
-use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{
BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety,
trait_ref: &TraitRef<'_>,
ty: Ty<'tcx>,
) {
- fn item_from_def_id<'tcx>(cx: &LateContext<'tcx>, def_id: DefId) -> &'tcx Item<'tcx> {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- cx.tcx.hir().expect_item(hir_id)
- }
-
fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
let mut visitor = UnsafeVisitor { cx, has_unsafe: false };
walk_item(&mut visitor, item);
if !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id);
if cx.tcx.inherent_impls(def.did)
.iter()
- .map(|imp_did| item_from_def_id(cx, *imp_did))
+ .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local()))
.any(|imp| has_unsafe(cx, imp));
then {
span_lint_and_help(
return;
}
let name = impl_item.ident.name.as_str();
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let item = cx.tcx.hir().expect_item(parent);
let self_ty = cx.tcx.type_of(item.def_id);
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind {
- let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id());
- let item = cx.tcx.hir().expect_item(item_hir_id);
+ let item_def_id = cx.tcx.hir().get_parent_did(impl_item.hir_id());
+ let item = cx.tcx.hir().expect_item(item_def_id);
match &item.kind {
ItemKind::Impl(Impl {
_ => return,
}
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let item = cx.tcx.hir().expect_item(parent);
let self_ty = cx.tcx.type_of(item.def_id);
let ret_ty = return_ty(cx, impl_item.hir_id());
if impl_item.span.from_expansion() {
return;
}
- let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
+ let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
let parent_item = cx.tcx.hir().expect_item(parent);
let assoc_item = cx.tcx.associated_item(impl_item.def_id);
if_chain! {
| |
| help: you might be missing a type parameter: `, VAL`
-error[E0283]: type annotations needed
- --> $DIR/ice-6252.rs:10:12
+error[E0046]: not all trait items implemented, missing: `VAL`
+ --> $DIR/ice-6252.rs:10:1
|
+LL | const VAL: T;
+ | ------------- `VAL` from trait
+...
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
- | ^^^^^^^^^^^^^^ cannot infer type for struct `Multiply<N, M>`
- |
- = note: cannot satisfy `Multiply<N, M>: TypeVal<usize>`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0283, E0412.
-For more information about an error, try `rustc --explain E0283`.
+Some errors have detailed explanations: E0046, E0412.
+For more information about an error, try `rustc --explain E0046`.
-Subproject commit 76a3329f51439ff2cacda4d26d478a9dc1682a06
+Subproject commit 9983e0fc634e11717eb457a73fe84cfc9409ba8f
-Subproject commit 183ef048f61ae36aa389d1d0345cde940fe788e9
+Subproject commit d9b2291f546abc77d24499339a72a89127464b95