Record more artifact sizes during self-profiling.
This PR adds artifact size recording for
- "linked artifacts" (executables, RLIBs, dylibs, static libs)
- object files
- dwo files
- assembly files
- crate metadata
- LLVM bitcode files
- LLVM IR files
- codegen unit size estimates
Currently the identifiers emitted for these are hard-coded as string literals. Is it worth adding constants to https://github.com/rust-lang/measureme/blob/master/measureme/src/rustc.rs instead? We don't do that for query names and the like -- but artifact kinds might be more stable than query names.
[[package]]
name = "curl"
-version = "0.4.39"
+version = "0.4.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aaa3b8db7f3341ddef15786d250106334d4a6c4b0ae4a46cd77082777d9849b9"
+checksum = "877cc2f9b8367e32b6dabb9d581557e651cb3aa693a37f8679091bbf42687d5d"
dependencies = [
"curl-sys",
"libc",
[[package]]
name = "curl-sys"
-version = "0.4.49+curl-7.79.1"
+version = "0.4.50+curl-7.79.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0f44960aea24a786a46907b8824ebc0e66ca06bf4e4978408c7499620343483"
+checksum = "4856b76919dd599f31236bb18db5f5bd36e2ce131e64f857ca5c259665b76171"
dependencies = [
"cc",
"libc",
i += 1;
}
// like the first, a last line of all stars should be omitted
- if j > i && lines[j - 1].chars().skip(1).all(|c| c == '*') {
+ if j > i && !lines[j - 1].is_empty() && lines[j - 1].chars().all(|c| c == '*') {
j -= 1;
}
// We generally shouldn't have errors here because the query was
// already run, but there's no point using `delay_span_bug`
// when we're going to emit an error here anyway.
- let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);
+ let _errors = fulfill_cx.select_all_or_error(infcx);
let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
debug!("{:#?}", region_constraints);
let param = generics.type_param(¶m_ty, tcx);
if let Some(generics) = tcx
.hir()
- .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id()))
+ .get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id()))
{
suggest_constraining_type_param(
tcx,
errors_buffer: &mut Vec<Diagnostic>,
) {
let tcx = infcx.tcx;
- let base_def_id = tcx.closure_base_def_id(body.source.def_id());
+ let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
if !tcx.has_attr(base_def_id, sym::rustc_regions) {
return;
}
// to store those. Otherwise, we'll pass in `None` to the
// functions below, which will trigger them to report errors
// eagerly.
- let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new);
+ let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
tcx,
closure_substs,
self.num_external_vids,
- tcx.closure_base_def_id(closure_def_id),
+ tcx.typeck_root_def_id(closure_def_id),
);
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::{Idx, IndexVec};
// though.
let category = match place.as_local() {
Some(RETURN_PLACE) => {
- if let BorrowCheckContext {
- universal_regions:
- UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
- ..
- } = self.borrowck_context
- {
- if tcx.is_static(*def_id) {
+ let defining_ty = &self.borrowck_context.universal_regions.defining_ty;
+ if defining_ty.is_const() {
+ if tcx.is_static(defining_ty.def_id()) {
ConstraintCategory::UseAsStatic
} else {
ConstraintCategory::UseAsConst
}
}
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
+ self.check_operand(discr, term_location);
+
let discr_ty = discr.ty(body, tcx);
if let Err(terr) = self.sub_types(
discr_ty,
// FIXME: check the values
}
TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
+ self.check_operand(func, term_location);
+ for arg in args {
+ self.check_operand(arg, term_location);
+ }
+
let func_ty = func.ty(body, tcx);
debug!("check_terminator: call, func_ty={:?}", func_ty);
let sig = match func_ty.kind() {
self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
}
TerminatorKind::Assert { ref cond, ref msg, .. } => {
+ self.check_operand(cond, term_location);
+
let cond_ty = cond.ty(body, tcx);
if cond_ty != tcx.types.bool {
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
}
}
TerminatorKind::Yield { ref value, .. } => {
+ self.check_operand(value, term_location);
+
let value_ty = value.ty(body, tcx);
match body.yield_ty() {
None => span_mirbug!(self, term, "yield in non-generator"),
Some(RETURN_PLACE) => {
if let BorrowCheckContext {
universal_regions:
- UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
+ UniversalRegions {
+ defining_ty:
+ DefiningTy::Const(def_id, _)
+ | DefiningTy::InlineConst(def_id, _),
+ ..
+ },
..
} = self.borrowck_context
{
}
}
+ fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
+ if let Operand::Constant(constant) = op {
+ let maybe_uneval = match constant.literal {
+ ConstantKind::Ty(ct) => match ct.val {
+ ty::ConstKind::Unevaluated(uv) => Some(uv),
+ _ => None,
+ },
+ _ => None,
+ };
+ if let Some(uv) = maybe_uneval {
+ if uv.promoted.is_none() {
+ let tcx = self.tcx();
+ let def_id = uv.def.def_id_for_type_of();
+ if tcx.def_kind(def_id) == DefKind::InlineConst {
+ let predicates = self.prove_closure_bounds(
+ tcx,
+ def_id.expect_local(),
+ uv.substs(tcx),
+ location,
+ );
+ self.normalize_and_prove_instantiated_predicates(
+ def_id,
+ predicates,
+ location.to_locations(),
+ );
+ }
+ }
+ }
+ }
+ }
+
fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
let tcx = self.tcx();
match rvalue {
Rvalue::Aggregate(ak, ops) => {
+ for op in ops {
+ self.check_operand(op, location);
+ }
self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
}
Rvalue::Repeat(operand, len) => {
+ self.check_operand(operand, location);
+
// If the length cannot be evaluated we must assume that the length can be larger
// than 1.
// If the length is larger than 1, the repeat expression will need to copy the
}
}
- Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
+ Rvalue::NullaryOp(_, ty) => {
+ let trait_ref = ty::TraitRef {
+ def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
+ substs: tcx.mk_substs_trait(ty, &[]),
+ };
+
+ self.prove_trait_ref(
+ trait_ref,
+ location.to_locations(),
+ ConstraintCategory::SizedBound,
+ );
+ }
+
+ Rvalue::ShallowInitBox(operand, ty) => {
+ self.check_operand(operand, location);
+
let trait_ref = ty::TraitRef {
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
substs: tcx.mk_substs_trait(ty, &[]),
}
Rvalue::Cast(cast_kind, op, ty) => {
+ self.check_operand(op, location);
+
match cast_kind {
CastKind::Pointer(PointerCast::ReifyFnPointer) => {
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
box (left, right),
) => {
+ self.check_operand(left, location);
+ self.check_operand(right, location);
+
let ty_left = left.ty(body, tcx);
match ty_left.kind() {
// Types with regions are comparable if they have a common super-type.
}
}
+ Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
+ self.check_operand(operand, location);
+ }
+
+ Rvalue::BinaryOp(_, box (left, right))
+ | Rvalue::CheckedBinaryOp(_, box (left, right)) => {
+ self.check_operand(left, location);
+ self.check_operand(right, location);
+ }
+
Rvalue::AddressOf(..)
| Rvalue::ThreadLocalRef(..)
- | Rvalue::Use(..)
| Rvalue::Len(..)
- | Rvalue::BinaryOp(..)
- | Rvalue::CheckedBinaryOp(..)
- | Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..) => {}
}
}
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
use std::iter;
use crate::nll::ToRegionVid;
/// is that it has no inputs and a single return value, which is
/// the value of the constant.
Const(DefId, SubstsRef<'tcx>),
+
+ /// The MIR represents an inline const. The signature has no inputs and a
+ /// single return value found via `InlineConstSubsts::ty`.
+ InlineConst(DefId, SubstsRef<'tcx>),
}
impl<'tcx> DefiningTy<'tcx> {
DefiningTy::Generator(_, substs, _) => {
Either::Right(Either::Left(substs.as_generator().upvar_tys()))
}
- DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
+ DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
Either::Right(Either::Right(iter::empty()))
}
}
pub fn implicit_inputs(self) -> usize {
match self {
DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1,
- DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0,
+ DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
}
}
}
pub fn is_const(&self) -> bool {
- matches!(*self, DefiningTy::Const(..))
+ matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
}
pub fn def_id(&self) -> DefId {
DefiningTy::Closure(def_id, ..)
| DefiningTy::Generator(def_id, ..)
| DefiningTy::FnDef(def_id, ..)
- | DefiningTy::Const(def_id, ..) => def_id,
+ | DefiningTy::Const(def_id, ..)
+ | DefiningTy::InlineConst(def_id, ..) => def_id,
}
}
}
tcx: TyCtxt<'tcx>,
closure_substs: SubstsRef<'tcx>,
expected_num_vars: usize,
- closure_base_def_id: DefId,
+ typeck_root_def_id: DefId,
) -> IndexVec<RegionVid, ty::Region<'tcx>> {
let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
region_mapping.push(tcx.lifetimes.re_static);
region_mapping.push(fr);
});
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
region_mapping.push(r);
});
// tests, and the resulting print-outs include def-ids
// and other things that are not stable across tests!
// So we just include the region-vid. Annoying.
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
});
}
// FIXME: As above, we'd like to print out the region
// `r` but doing so is not stable across architectures
// and so forth.
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
});
}
tcx.def_path_str_with_substs(def_id, substs),
));
}
+ DefiningTy::InlineConst(def_id, substs) => {
+ err.note(&format!(
+ "defining inline constant type: {}",
+ tcx.def_path_str_with_substs(def_id, substs),
+ ));
+ }
}
}
}
let mut indices = self.compute_indices(fr_static, defining_ty);
debug!("build: indices={:?}", indices);
- let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+ let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
// If this is a closure or generator, then the late-bound regions from the enclosing
// function are actually external regions to us. For example, here, 'a is not local
// fn foo<'a>() {
// let c = || { let x: &'a u32 = ...; }
// }
- if self.mir_def.did.to_def_id() != closure_base_def_id {
+ if self.mir_def.did.to_def_id() != typeck_root_def_id {
self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
}
);
// Converse of above, if this is a function then the late-bound regions declared on its
// signature are local to the fn.
- if self.mir_def.did.to_def_id() == closure_base_def_id {
+ if self.mir_def.did.to_def_id() == typeck_root_def_id {
self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
}
/// see `DefiningTy` for details.
fn defining_ty(&self) -> DefiningTy<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+ let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
match tcx.hir().body_owner_kind(self.mir_hir_id) {
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
- let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id {
- tcx.type_of(closure_base_def_id)
+ let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
+ tcx.type_of(typeck_root_def_id)
} else {
let tables = tcx.typeck(self.mir_def.did);
tables.node_type(self.mir_hir_id)
}
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
- assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
- let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
- let substs =
- self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
- DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+ let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
+ if self.mir_def.did.to_def_id() == typeck_root_def_id {
+ let substs =
+ self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
+ DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+ } else {
+ let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
+ let substs = InlineConstSubsts::new(
+ tcx,
+ InlineConstSubstsParts { parent_substs: identity_substs, ty },
+ )
+ .substs;
+ let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs);
+ DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs)
+ }
}
}
}
defining_ty: DefiningTy<'tcx>,
) -> UniversalRegionIndices<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
- let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
+ let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
let fr_substs = match defining_ty {
- DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
+ DefiningTy::Closure(_, ref substs)
+ | DefiningTy::Generator(_, ref substs, _)
+ | DefiningTy::InlineConst(_, ref substs) => {
// In the case of closures, we rely on the fact that
// the first N elements in the ClosureSubsts are
- // inherited from the `closure_base_def_id`.
+ // inherited from the `typeck_root_def_id`.
// Therefore, when we zip together (below) with
// `identity_substs`, we will get only those regions
// that correspond to early-bound regions declared on
- // the `closure_base_def_id`.
+ // the `typeck_root_def_id`.
assert!(substs.len() >= identity_substs.len());
assert_eq!(substs.regions().count(), identity_substs.regions().count());
substs
let ty = indices.fold_to_region_vids(tcx, ty);
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
}
+
+ DefiningTy::InlineConst(def_id, substs) => {
+ assert_eq!(self.mir_def.did.to_def_id(), def_id);
+ let ty = substs.as_inline_const().ty();
+ ty::Binder::dummy(tcx.intern_type_list(&[ty]))
+ }
}
}
}
indices: &mut UniversalRegionIndices<'tcx>,
) {
debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
- let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
- for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
+ for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR);
/// Actually builds the expression which the format_args! block will be
/// expanded to.
fn into_expr(self) -> P<ast::Expr> {
- let mut locals =
- Vec::with_capacity((0..self.args.len()).map(|i| self.arg_unique_types[i].len()).sum());
- let mut counts = Vec::with_capacity(self.count_args.len());
- let mut pats = Vec::with_capacity(self.args.len());
+ let mut args = Vec::with_capacity(
+ self.arg_unique_types.iter().map(|v| v.len()).sum::<usize>() + self.count_args.len(),
+ );
let mut heads = Vec::with_capacity(self.args.len());
- let names_pos: Vec<_> = (0..self.args.len())
- .map(|i| Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
- .collect();
-
// First, build up the static array which will become our precompiled
// format "string"
let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces);
// of each variable because we don't want to move out of the arguments
// passed to this function.
for (i, e) in self.args.into_iter().enumerate() {
- let name = names_pos[i];
- let span = self.ecx.with_def_site_ctxt(e.span);
- pats.push(self.ecx.pat_ident(span, name));
for arg_ty in self.arg_unique_types[i].iter() {
- locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name));
+ args.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, i));
}
heads.push(self.ecx.expr_addr_of(e.span, e));
}
Exact(i) => i,
_ => panic!("should never happen"),
};
- let name = names_pos[index];
let span = spans_pos[index];
- counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, name));
+ args.push(Context::format_arg(self.ecx, self.macsp, span, &Count, index));
}
- // Now create a vector containing all the arguments
- let args = locals.into_iter().chain(counts.into_iter());
-
- let args_array = self.ecx.expr_vec(self.macsp, args.collect());
+ let args_array = self.ecx.expr_vec(self.macsp, args);
// Constructs an AST equivalent to:
//
// But the nested match expression is proved to perform not as well
// as series of let's; the first approach does.
let args_match = {
- let pat = self.ecx.pat_tuple(self.macsp, pats);
+ let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::_args, self.macsp));
let arm = self.ecx.arm(self.macsp, pat, args_array);
let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
self.ecx.expr_match(self.macsp, head, vec![arm])
macsp: Span,
mut sp: Span,
ty: &ArgumentType,
- arg: Ident,
+ arg_index: usize,
) -> P<ast::Expr> {
sp = ecx.with_def_site_ctxt(sp);
- let arg = ecx.expr_ident(sp, arg);
+ let arg = ecx.expr_ident(sp, Ident::new(sym::_args, sp));
+ let arg = ecx.expr(sp, ast::ExprKind::Field(arg, Ident::new(sym::integer(arg_index), sp)));
let trait_ = match *ty {
Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true),
Placeholder(trait_) => trait_,
cookie = 0;
}
let level = match level {
- llvm::DiagnosticLevel::Error => Level::Error,
+ llvm::DiagnosticLevel::Error => Level::Error { lint: false },
llvm::DiagnosticLevel::Warning => Level::Warning,
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
};
type_names::push_item_name(self.tcx(), def_id, false, &mut name);
// Find the enclosing function, in case this is a closure.
- let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
+ let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id);
// Get_template_parameters() will append a `<...>` clause to the function
// name if necessary.
let msg = msg.strip_prefix("error: ").unwrap_or(&msg);
let mut err = match level {
- Level::Error => sess.struct_err(&msg),
+ Level::Error { lint: false } => sess.struct_err(&msg),
Level::Warning => sess.struct_warn(&msg),
Level::Note => sess.struct_note_without_error(&msg),
_ => bug!("Invalid inline asm diagnostic level"),
("aes", Some(sym::arm_target_feature)),
("sha2", Some(sym::arm_target_feature)),
("i8mm", Some(sym::arm_target_feature)),
+ ("dotprod", Some(sym::arm_target_feature)),
("v5te", Some(sym::arm_target_feature)),
("v6", Some(sym::arm_target_feature)),
("v6k", Some(sym::arm_target_feature)),
| DefKind::Static
| DefKind::ConstParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::AssocConst
),
"Unexpected DefKind: {:?}",
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);
- if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(&err, None, false);
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
}
});
}
/// Maps `Diagnostic::Level` to `snippet::AnnotationType`
fn annotation_type_for_level(level: Level) -> AnnotationType {
match level {
- Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error,
+ Level::Bug | Level::Fatal | Level::Error { .. } => AnnotationType::Error,
Level::Warning => AnnotationType::Warning,
Level::Note => AnnotationType::Note,
Level::Help => AnnotationType::Help,
pub fn is_error(&self) -> bool {
match self.level {
- Level::Bug | Level::Fatal | Level::Error | Level::FailureNote => true,
+ Level::Bug | Level::Fatal | Level::Error { .. } | Level::FailureNote => true,
Level::Warning | Level::Note | Level::Help | Level::Cancelled | Level::Allow => false,
}
/// as well as inconsistent state observation.
struct HandlerInner {
flags: HandlerFlags,
+ /// The number of lint errors that have been emitted.
+ lint_err_count: usize,
/// The number of errors that have been emitted, including duplicates.
///
/// This is not necessarily the count that's reported to the user once
flags,
inner: Lock::new(HandlerInner {
flags,
+ lint_err_count: 0,
err_count: 0,
warn_count: 0,
deduplicated_err_count: 0,
/// Construct a builder at the `Error` level with the `msg`.
// FIXME: This method should be removed (every error should have an associated error code).
pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
- DiagnosticBuilder::new(self, Level::Error, msg)
+ DiagnosticBuilder::new(self, Level::Error { lint: false }, msg)
+ }
+
+ /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
+ #[doc(hidden)]
+ pub fn struct_err_lint(&self, msg: &str) -> DiagnosticBuilder<'_> {
+ DiagnosticBuilder::new(self, Level::Error { lint: true }, msg)
}
/// Construct a builder at the `Error` level with the `msg` and the `code`.
}
pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) {
- self.emit_diag_at_span(Diagnostic::new(Error, msg), span);
+ self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span);
}
pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
- self.emit_diag_at_span(Diagnostic::new_with_code(Error, Some(code), msg), span);
+ self.emit_diag_at_span(
+ Diagnostic::new_with_code(Error { lint: false }, Some(code), msg),
+ span,
+ );
}
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) {
pub fn has_errors(&self) -> bool {
self.inner.borrow().has_errors()
}
+ pub fn has_errors_or_lint_errors(&self) -> bool {
+ self.inner.borrow().has_errors_or_lint_errors()
+ }
pub fn has_errors_or_delayed_span_bugs(&self) -> bool {
self.inner.borrow().has_errors_or_delayed_span_bugs()
}
}
}
if diagnostic.is_error() {
- self.bump_err_count();
+ if matches!(diagnostic.level, Level::Error { lint: true }) {
+ self.bump_lint_err_count();
+ } else {
+ self.bump_err_count();
+ }
} else {
self.bump_warn_count();
}
fn has_errors(&self) -> bool {
self.err_count() > 0
}
+ fn has_errors_or_lint_errors(&self) -> bool {
+ self.has_errors() || self.lint_err_count > 0
+ }
fn has_errors_or_delayed_span_bugs(&self) -> bool {
self.has_errors() || !self.delayed_span_bugs.is_empty()
}
fn has_any_message(&self) -> bool {
- self.err_count() > 0 || self.warn_count > 0
+ self.err_count() > 0 || self.lint_err_count > 0 || self.warn_count > 0
}
fn abort_if_errors(&mut self) {
}
fn err(&mut self, msg: &str) {
- self.emit_error(Error, msg);
+ self.emit_error(Error { lint: false }, msg);
}
/// Emit an error; level should be `Error` or `Fatal`.
}
}
+ fn bump_lint_err_count(&mut self) {
+ self.lint_err_count += 1;
+ self.panic_if_treat_err_as_bug();
+ }
+
fn bump_err_count(&mut self) {
self.err_count += 1;
self.panic_if_treat_err_as_bug();
pub enum Level {
Bug,
Fatal,
- Error,
+ Error {
+ /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called.
+ lint: bool,
+ },
Warning,
Note,
Help,
fn color(self) -> ColorSpec {
let mut spec = ColorSpec::new();
match self {
- Bug | Fatal | Error => {
+ Bug | Fatal | Error { .. } => {
spec.set_fg(Some(Color::Red)).set_intense(true);
}
Warning => {
pub fn to_str(self) -> &'static str {
match self {
Bug => "error: internal compiler error",
- Fatal | Error => "error",
+ Fatal | Error { .. } => "error",
Warning => "warning",
Note => "note",
Help => "help",
impl ToInternal<rustc_errors::Level> for Level {
fn to_internal(self) -> rustc_errors::Level {
match self {
- Level::Error => rustc_errors::Level::Error,
+ Level::Error => rustc_errors::Level::Error { lint: false },
Level::Warning => rustc_errors::Level::Warning,
Level::Note => rustc_errors::Level::Note,
Level::Help => rustc_errors::Level::Help,
Use,
/// An `extern` block.
ForeignMod,
- /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`, or `const { 1 + 2}`
+ /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`
AnonConst,
+ /// An inline constant, e.g. `const { 1 + 2 }`
+ InlineConst,
/// Opaque type, aka `impl Trait`.
OpaqueTy,
Field,
DefKind::Use => "import",
DefKind::ForeignMod => "foreign module",
DefKind::AnonConst => "constant expression",
+ DefKind::InlineConst => "inline constant",
DefKind::Field => "field",
DefKind::Impl => "implementation",
DefKind::Closure => "closure",
| DefKind::OpaqueTy
| DefKind::Impl
| DefKind::Use
+ | DefKind::InlineConst
| DefKind::ExternCrate => "an",
DefKind::Macro(macro_kind) => macro_kind.article(),
_ => "a",
// Not namespaced.
DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::ExternCrate
let tcx = self.tcx;
// Select everything, returning errors.
- let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new);
+ let true_errors = fulfill_cx.select_where_possible(self);
debug!("true_errors = {:#?}", true_errors);
if !true_errors.is_empty() {
}
// Anything left unselected *now* must be an ambiguity.
- let ambig_errors = fulfill_cx.select_all_or_error(self).err().unwrap_or_else(Vec::new);
+ let ambig_errors = fulfill_cx.select_all_or_error(self);
debug!("ambig_errors = {:#?}", ambig_errors);
let region_obligations = self.take_registered_region_obligations();
/// function. We can then add implied bounds and the like from the
/// closure arguments into the environment -- these should only
/// apply in the closure body, so once we exit, we invoke
- /// `pop_snapshot_post_closure` to remove them.
+ /// `pop_snapshot_post_typeck_child` to remove them.
///
/// Example:
///
/// seems like it'd be readily fixed if we wanted. There are
/// similar leaks around givens that seem equally suspicious, to
/// be honest. --nmatsakis
- pub fn push_snapshot_pre_closure(&self) -> usize {
+ pub fn push_snapshot_pre_typeck_child(&self) -> usize {
self.region_bound_pairs_accum.len()
}
- /// See `push_snapshot_pre_closure`.
- pub fn pop_snapshot_post_closure(&mut self, len: usize) {
+ /// See `push_snapshot_pre_typeck_child`.
+ pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) {
self.region_bound_pairs_accum.truncate(len);
}
obligation: PredicateObligation<'tcx>,
);
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>>;
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;
fn select_all_with_constness_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
_constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
self.select_all_or_error(infcx)
}
- fn select_where_possible(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>>;
+ fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
+ -> Vec<FulfillmentError<'tcx>>;
// FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated
fn select_with_constness_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
_constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
self.select_where_possible(infcx)
}
| DefKind::ConstParam
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
DefKind::Use
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
(true, mir_opt_base)
}
// Constants
- DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => {
- (true, false)
- }
+ DefKind::AnonConst
+ | DefKind::InlineConst
+ | DefKind::AssocConst
+ | DefKind::Static
+ | DefKind::Const => (true, false),
// Full-fledged functions
DefKind::AssocFn | DefKind::Fn => {
let generics = tcx.generics_of(def_id);
| DefKind::Use
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
| DefKind::AssocFn
| DefKind::AssocConst
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Impl
| DefKind::Field
};
DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data))
}
- Node::AnonConst(_) => DefKind::AnonConst,
+ Node::AnonConst(_) => {
+ let inline = match self.find(self.get_parent_node(hir_id)) {
+ Some(Node::Expr(&Expr {
+ kind: ExprKind::ConstBlock(ref anon_const), ..
+ })) if anon_const.hir_id == hir_id => true,
+ _ => false,
+ };
+ if inline { DefKind::InlineConst } else { DefKind::AnonConst }
+ }
Node::Field(_) => DefKind::Field,
Node::Expr(expr) => match expr.kind {
ExprKind::Closure(.., None) => DefKind::Closure,
(Level::Warn, None) => sess.struct_warn(""),
(Level::ForceWarn, Some(span)) => sess.struct_span_force_warn(span, ""),
(Level::ForceWarn, None) => sess.struct_force_warn(""),
- (Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
- (Level::Deny | Level::Forbid, None) => sess.struct_err(""),
+ (Level::Deny | Level::Forbid, Some(span)) => {
+ let mut builder = sess.diagnostic().struct_err_lint("");
+ builder.set_span(span);
+ builder
+ }
+ (Level::Deny | Level::Forbid, None) => sess.diagnostic().struct_err_lint(""),
};
// If this code originates in a foreign macro, aka something that this crate
write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })?
}
(_, _) if is_function => write!(w, "fn ")?,
- (DefKind::AnonConst, _) => {} // things like anon const, not an item
+ (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
_ => bug!("Unexpected def kind {:?}", kind),
}
/// additional requirements that the closure's creator must verify.
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) }
+ cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
}
query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc {
use crate::mir::interpret::ConstValue;
use crate::mir::interpret::{LitToConstInput, Scalar};
-use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::{ParamEnv, ParamEnvAnd};
+use crate::ty::{
+ self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
+ TyCtxt, TypeFoldable,
+};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
let ty = tcx.type_of(def.def_id_for_type_of());
+ match Self::try_eval_lit_or_param(tcx, ty, expr) {
+ Some(v) => v,
+ None => tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: def.to_global(),
+ substs_: None,
+ promoted: None,
+ }),
+ ty,
+ }),
+ }
+ }
+
+ fn try_eval_lit_or_param(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ ) -> Option<&'tcx Self> {
let lit_input = match expr.kind {
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
// If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir.
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
- return c;
+ return Some(c);
} else {
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
}
};
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
- let val = match expr.kind {
+ match expr.kind {
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
// Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`.
let generics = tcx.generics_of(item_def_id.to_def_id());
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.hir().name(hir_id);
- ty::ConstKind::Param(ty::ParamConst::new(index, name))
+ Some(tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
+ ty,
+ }))
}
- _ => ty::ConstKind::Unevaluated(ty::Unevaluated {
- def: def.to_global(),
- substs_: None,
- promoted: None,
- }),
+ _ => None,
+ }
+ }
+
+ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+ debug!("Const::from_inline_const(def_id={:?})", def_id);
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+ let body_id = match tcx.hir().get(hir_id) {
+ hir::Node::AnonConst(ac) => ac.body,
+ _ => span_bug!(
+ tcx.def_span(def_id.to_def_id()),
+ "from_inline_const can only process anonymous constants"
+ ),
};
- tcx.mk_const(ty::Const { val, ty })
+ let expr = &tcx.hir().body(body_id).value;
+
+ let ty = tcx.typeck(def_id).node_type(hir_id);
+
+ let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) {
+ Some(v) => v,
+ None => {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
+ let parent_substs =
+ tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
+ let substs =
+ InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
+ .substs;
+ tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: ty::WithOptConstParam::unknown(def_id).to_global(),
+ substs_: Some(substs),
+ promoted: None,
+ }),
+ ty,
+ })
+ }
+ };
+ debug_assert!(!ret.has_free_regions(tcx));
+ ret
}
/// Interns the given value as a constant.
TupleSize(ExpectedFound<usize>),
FixedArraySize(ExpectedFound<u64>),
ArgCount,
+ FieldMisMatch(Symbol, Symbol),
RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>),
pluralize!(values.found)
),
ArgCount => write!(f, "incorrect number of function parameters"),
+ FieldMisMatch(adt, field) => write!(f, "field type mismatch: {}.{}", adt, field),
RegionsDoesNotOutlive(..) => write!(f, "lifetime mismatch"),
RegionsInsufficientlyPolymorphic(br, _) => write!(
f,
| ArgumentMutability(_)
| TupleSize(_)
| ArgCount
+ | FieldMisMatch(..)
| RegionsDoesNotOutlive(..)
| RegionsInsufficientlyPolymorphic(..)
| RegionsOverlyPolymorphic(..)
Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion,
ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
- GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
- PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
- RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
+ GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
+ ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
+ PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
+ UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
};
pub use self::trait_def::TraitDef;
| DefKind::Static
| DefKind::AssocConst
| DefKind::Ctor(..)
- | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def),
+ | DefKind::AnonConst
+ | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
// If the caller wants `mir_for_ctfe` of a function they should not be using
// `instance_mir`, so we'll assume const fn also wants the optimized version.
_ => {
TupleSize(x) => TupleSize(x),
FixedArraySize(x) => FixedArraySize(x),
ArgCount => ArgCount,
+ FieldMisMatch(x, y) => FieldMisMatch(x, y),
RegionsDoesNotOutlive(a, b) => {
return tcx.lift((a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b));
}
}
}
+/// An inline const is modeled like
+///
+/// const InlineConst<'l0...'li, T0...Tj, R>: R;
+///
+/// where:
+///
+/// - 'l0...'li and T0...Tj are the generic parameters
+/// inherited from the item that defined the inline const,
+/// - R represents the type of the constant.
+///
+/// When the inline const is instantiated, `R` is substituted as the actual inferred
+/// type of the constant. The reason that `R` is represented as an extra type parameter
+/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters:
+/// inline const can reference lifetimes that are internal to the creating function.
+#[derive(Copy, Clone, Debug, TypeFoldable)]
+pub struct InlineConstSubsts<'tcx> {
+ /// Generic parameters from the enclosing item,
+ /// concatenated with the inferred type of the constant.
+ pub substs: SubstsRef<'tcx>,
+}
+
+/// Struct returned by `split()`.
+pub struct InlineConstSubstsParts<'tcx, T> {
+ pub parent_substs: &'tcx [GenericArg<'tcx>],
+ pub ty: T,
+}
+
+impl<'tcx> InlineConstSubsts<'tcx> {
+ /// Construct `InlineConstSubsts` from `InlineConstSubstsParts`.
+ pub fn new(
+ tcx: TyCtxt<'tcx>,
+ parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>,
+ ) -> InlineConstSubsts<'tcx> {
+ InlineConstSubsts {
+ substs: tcx.mk_substs(
+ parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())),
+ ),
+ }
+ }
+
+ /// Divides the inline const substs into their respective components.
+ /// The ordering assumed here must match that used by `InlineConstSubsts::new` above.
+ fn split(self) -> InlineConstSubstsParts<'tcx, GenericArg<'tcx>> {
+ match self.substs[..] {
+ [ref parent_substs @ .., ty] => InlineConstSubstsParts { parent_substs, ty },
+ _ => bug!("inline const substs missing synthetics"),
+ }
+ }
+
+ /// Returns the substitutions of the inline const's parent.
+ pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+ self.split().parent_substs
+ }
+
+ /// Returns the type of this inline const.
+ pub fn ty(self) -> Ty<'tcx> {
+ self.split().ty.expect_ty()
+ }
+}
+
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub enum ExistentialPredicate<'tcx> {
use crate::mir;
use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
+use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
use rustc_hir::def_id::DefId;
GeneratorSubsts { substs: self }
}
+ /// Interpret these substitutions as the substitutions of an inline const.
+ /// Inline const substitutions have a particular structure controlled by the
+ /// compiler that encodes information like the inferred type;
+ /// see `ty::InlineConstSubsts` struct for more comments.
+ pub fn as_inline_const(&'tcx self) -> InlineConstSubsts<'tcx> {
+ InlineConstSubsts { substs: self }
+ }
+
/// Creates an `InternalSubsts` that maps each generic parameter to itself.
pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))
matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator)
}
+ /// Returns `true` if `def_id` refers to a definition that does not have its own
+ /// type-checking context, i.e. closure, generator or inline const.
+ pub fn is_typeck_child(self, def_id: DefId) -> bool {
+ matches!(
+ self.def_kind(def_id),
+ DefKind::Closure | DefKind::Generator | DefKind::InlineConst
+ )
+ }
+
/// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
pub fn is_trait(self, def_id: DefId) -> bool {
self.def_kind(def_id) == DefKind::Trait
matches!(self.def_kind(def_id), DefKind::Ctor(..))
}
- /// Given the def-ID of a fn or closure, returns the def-ID of
- /// the innermost fn item that the closure is contained within.
- /// This is a significant `DefId` because, when we do
- /// type-checking, we type-check this fn item and all of its
- /// (transitive) closures together. Therefore, when we fetch the
+ /// Given the `DefId`, returns the `DefId` of the innermost item that
+ /// has its own type-checking context or "inference enviornment".
+ ///
+ /// For example, a closure has its own `DefId`, but it is type-checked
+ /// with the containing item. Similarly, an inline const block has its
+ /// own `DefId` but it is type-checked together with the containing item.
+ ///
+ /// Therefore, when we fetch the
/// `typeck` the closure, for example, we really wind up
/// fetching the `typeck` the enclosing fn item.
- pub fn closure_base_def_id(self, def_id: DefId) -> DefId {
+ pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
let mut def_id = def_id;
- while self.is_closure(def_id) {
+ while self.is_typeck_child(def_id) {
def_id = self.parent(def_id).unwrap_or_else(|| {
bug!("closure {:?} has no parent", def_id);
});
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
- let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+ let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
ExprKind::ConstBlock { value }
}
let (lit, neg) = match expr.kind {
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
- let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+ let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
if matches!(value.val, ConstKind::Param(_)) {
let span = self.tcx.hir().span(anon_const.hir_id);
self.errors.push(PatternError::ConstParamInPattern(span));
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
generics: &'tcx ty::Generics,
unused_parameters: &FiniteBitSet<u32>,
) {
- let base_def_id = tcx.closure_base_def_id(def_id);
+ let base_def_id = tcx.typeck_root_def_id(def_id);
if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) {
return;
}
ControlFlow::CONTINUE
}
ty::ConstKind::Unevaluated(uv)
- if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst =>
+ if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) =>
{
self.visit_child_body(uv.def.did, uv.substs(self.tcx));
ControlFlow::CONTINUE
// properly, we can't miss any types.
match expr.kind {
- // Manually recurse over closures, because they are the only
+ // Manually recurse over closures and inline consts, because they are the only
// case of nested bodies that share the parent environment.
- hir::ExprKind::Closure(.., body, _, _) => {
+ hir::ExprKind::Closure(.., body, _, _)
+ | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
let body = visitor.tcx.hir().body(body);
visitor.visit_body(body);
}
}
fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- if closure_base_def_id != def_id {
- return tcx.region_scope_tree(closure_base_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ if typeck_root_def_id != def_id {
+ return tcx.region_scope_tree(typeck_root_def_id);
}
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::GlobalAsm
| DefKind::Impl
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
if let Some(result) = result {
+ let prev_fingerprint = tcx
+ .dep_context()
+ .dep_graph()
+ .prev_fingerprint_of(dep_node)
+ .unwrap_or(Fingerprint::ZERO);
// If `-Zincremental-verify-ich` is specified, re-hash results from
// the cache and make sure that they have the expected fingerprint.
- if unlikely!(tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich) {
+ //
+ // If not, we still seek to verify a subset of fingerprints loaded
+ // from disk. Re-hashing results is fairly expensive, so we can't
+ // currently afford to verify every hash. This subset should still
+ // give us some coverage of potential bugs though.
+ let try_verify = prev_fingerprint.as_value().1 % 32 == 0;
+ if unlikely!(
+ try_verify || tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich
+ ) {
incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
}
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::GlobalAsm
def_id: LocalDefId,
) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
match tcx.def_kind(def_id) {
- DefKind::AnonConst => {
+ DefKind::AnonConst | DefKind::InlineConst => {
let mut def_id = tcx
.parent(def_id.to_def_id())
.unwrap_or_else(|| bug!("anon const or closure without a parent"));
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = c
.generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
- })
+ .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param);
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) =
bound_generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
+ .filter(|param| {
+ matches!(param.kind, GenericParamKind::Lifetime { .. })
})
.enumerate()
.map(|(late_bound_idx, param)| {
let binders_iter = trait_ref
.bound_generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
- })
+ .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(
let binders: Vec<_> = generics
.params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. }
- if self.map.late_bound.contains(¶m.hir_id) =>
- {
- Some(param)
- }
- _ => None,
+ .filter(|param| {
+ matches!(param.kind, GenericParamKind::Lifetime { .. })
+ && self.map.late_bound.contains(¶m.hir_id)
})
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param);
- let r = late_region_as_bound_region(self.tcx, &pair.1);
- r
+ late_region_as_bound_region(self.tcx, &pair.1)
})
.collect();
self.map.late_bound_vars.insert(hir_id, binders);
| HirDefKind::ForeignMod
| HirDefKind::LifetimeParam
| HirDefKind::AnonConst
+ | HirDefKind::InlineConst
| HirDefKind::Use
| HirDefKind::Field
| HirDefKind::GlobalAsm
self.diagnostic().abort_if_errors();
}
pub fn compile_status(&self) -> Result<(), ErrorReported> {
- if self.has_errors() {
+ if self.diagnostic().has_errors_or_lint_errors() {
self.diagnostic().emit_stashed_diagnostics();
Err(ErrorReported)
} else {
__S,
__next,
__try_var,
+ _args,
_d,
_e,
_task_context,
-use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{LinkArgs, LinkerFlavor, RelocModel, Target, TargetOptions};
/// A base target for Nintendo 3DS devices using the devkitARM toolchain.
///
features: "+vfp2".to_string(),
pre_link_args,
exe_suffix: ".elf".to_string(),
- panic_strategy: PanicStrategy::Abort,
..Default::default()
},
}
},
cause,
);
- if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
+ let errors = fulfillcx.select_where_possible(&self.infcx);
+ if !errors.is_empty() {
// This shouldn't happen, except for evaluate/fulfill mismatches,
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
// by design).
- debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
+ debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors);
return None;
}
let obligations = fulfillcx.pending_obligations();
// an additional sanity check.
let mut fulfill = FulfillmentContext::new();
fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
- fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| {
- panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, e)
- });
+ let errors = fulfill.select_all_or_error(&infcx);
+
+ if !errors.is_empty() {
+ panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
+ }
let body_id_map: FxHashMap<_, _> = infcx
.inner
self.obligations.insert(obligation);
}
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_where_possible(infcx)?;
-
- if self.obligations.is_empty() {
- Ok(())
- } else {
- let errors = self
- .obligations
- .iter()
- .map(|obligation| FulfillmentError {
- obligation: obligation.clone(),
- code: FulfillmentErrorCode::CodeAmbiguity,
- // FIXME - does Chalk have a notation of 'root obligation'?
- // This is just for diagnostics, so it's okay if this is wrong
- root_obligation: obligation.clone(),
- })
- .collect();
- Err(errors)
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_where_possible(infcx);
+
+ if !errors.is_empty() {
+ return errors;
+ }
}
+
+ // any remaining obligations are errors
+ self.obligations
+ .iter()
+ .map(|obligation| FulfillmentError {
+ obligation: obligation.clone(),
+ code: FulfillmentErrorCode::CodeAmbiguity,
+ // FIXME - does Chalk have a notation of 'root obligation'?
+ // This is just for diagnostics, so it's okay if this is wrong
+ root_obligation: obligation.clone(),
+ })
+ .collect()
}
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
assert!(!infcx.is_in_snapshot());
let mut errors = Vec::new();
}
}
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ errors
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
- if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
&format!("Encountered errors `{:?}` resolving bounds after type-checking", errors),
if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
match infcx.tcx.def_kind(uv.def.did) {
- DefKind::AnonConst => {
+ DefKind::AnonConst | DefKind::InlineConst => {
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
if mir_body.is_polymorphic {
// we want to look into them or treat them as opaque projections.
//
// Right now we do neither of that and simply always fail to unify them.
- DefKind::AnonConst => (),
+ DefKind::AnonConst | DefKind::InlineConst => (),
_ => return Ok(None),
}
let span = self.tcx.def_span(generator_did);
let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
- let generator_did_root = self.tcx.closure_base_def_id(generator_did);
+ let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
debug!(
"maybe_note_obligation_cause_for_async_await: generator_did={:?} \
generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}",
}
/// Attempts to select obligations using `selcx`.
- fn select(
- &mut self,
- selcx: &mut SelectionContext<'a, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
let _enter = span.enter();
errors.len()
);
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ errors
}
}
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_where_possible(infcx)?;
-
- let errors: Vec<_> = self
- .predicates
- .to_errors(CodeAmbiguity)
- .into_iter()
- .map(to_fulfillment_error)
- .collect();
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_where_possible(infcx);
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
+
+ self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
fn select_all_with_constness_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: rustc_hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_with_constness_where_possible(infcx, constness)?;
-
- let errors: Vec<_> = self
- .predicates
- .to_errors(CodeAmbiguity)
- .into_iter()
- .map(to_fulfillment_error)
- .collect();
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ ) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_with_constness_where_possible(infcx, constness);
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
+
+ self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::new(infcx);
self.select(&mut selcx)
}
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::with_constness(infcx, constness);
self.select(&mut selcx)
}
// Note: we only assume something is `Copy` if we can
// *definitively* show that it implements `Copy`. Otherwise,
// assume it is move; linear is always ok.
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => {
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => {
debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
ty,
);
true
}
- Err(e) => {
+ errors => {
debug!(
- "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}",
- ty,
- infcx.tcx.def_path_str(def_id),
- e
+ ?ty,
+ bound = %infcx.tcx.def_path_str(def_id),
+ ?errors,
+ "type_known_to_meet_bound_modulo_regions"
);
false
}
}
debug!("fully_normalize: select_all_or_error start");
- fulfill_cx.select_all_or_error(infcx)?;
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
+ return Err(errors);
+ }
debug!("fully_normalize: select_all_or_error complete");
let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
debug!("fully_normalize: resolved_value={:?}", resolved_value);
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
- fulfill_cx.select_all_or_error(&infcx).is_err()
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+
+ !errors.is_empty()
});
debug!("impossible_predicates = {:?}", result);
result
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(infcx, obligations);
- if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP,
- &format!("errors selecting obligation during MIR typeck: {:?}", e),
+ &format!("errors selecting obligation during MIR typeck: {:?}", errors),
);
}
for oblig in obligations.chain(more_obligations) {
fulfill_cx.register_predicate_obligation(&infcx, oblig);
}
- match fulfill_cx.select_all_or_error(infcx) {
- Err(errors) => {
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => {
+ debug!(
+ "fulfill_implication: an impl for {:?} specializes {:?}",
+ source_trait_ref, target_trait_ref
+ );
+
+ // Now resolve the *substitution* we built for the target earlier, replacing
+ // the inference variables inside with whatever we got from fulfillment.
+ Ok(infcx.resolve_vars_if_possible(target_substs))
+ }
+ errors => {
// no dice!
debug!(
"fulfill_implication: for impls on {:?} and {:?}, \
);
Err(())
}
-
- Ok(()) => {
- debug!(
- "fulfill_implication: an impl for {:?} specializes {:?}",
- source_trait_ref, target_trait_ref
- );
-
- // Now resolve the *substitution* we built for the target earlier, replacing
- // the inference variables inside with whatever we got from fulfillment.
- Ok(infcx.resolve_vars_if_possible(target_substs))
- }
}
})
}
//
// 2. We are sometimes doing future-incompatibility lints for
// now, so we do not want unconditional errors here.
- fulfillment_cx.select_all_or_error(infcx).is_ok()
+ fulfillment_cx.select_all_or_error(infcx).is_empty()
}
/// This implements the traversal over the structure of a given type to try to
// Ensure that those obligations that we had to solve
// get solved *here*.
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => Ok(implied_bounds),
- Err(_) => Err(NoSolution),
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => Ok(implied_bounds),
+ _ => Err(NoSolution),
}
}
err.span_label(span, "explicit generic argument not allowed");
}
+ err.note(
+ "see issue #83701 <https://github.com/rust-lang/rust/issues/83701> \
+ for more information",
+ );
+ if tcx.sess.is_nightly_build() {
+ err.help(
+ "add `#![feature(explicit_generic_args_with_impl_trait)]` \
+ to the crate attributes to enable",
+ );
+ }
+
err.emit();
}
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
}
// Finally, resolve all regions. This catches wily misuses of
let parent_substs = InternalSubsts::identity_for_item(
self.tcx,
- self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
+ self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
);
let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
};
let mut fcx = traits::FulfillmentContext::new_in_snapshot();
fcx.register_predicate_obligations(self, ok.obligations);
- fcx.select_where_possible(&self).is_ok()
+ fcx.select_where_possible(&self).is_empty()
})
}
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return;
}
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) =
- inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness)
- {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors =
+ inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
}
}
- if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
// this could be reached when we get lazy normalization
- infcx.report_fulfillment_errors(errors, None, false);
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, QPath};
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::InferOk;
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
+use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts};
+use rustc_middle::ty::relate::expected_found_bool;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::Ty;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{AdtKind, Visibility};
+use rustc_session::parse::feature_err;
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
}
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
- ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty,
+ ExprKind::ConstBlock(ref anon_const) => {
+ self.check_expr_const_block(anon_const, expected, expr)
+ }
ExprKind::Repeat(element, ref count) => {
self.check_expr_repeat(element, count, expected, expr)
}
self.tcx.mk_array(element_ty, args.len() as u64)
}
+ fn check_expr_const_block(
+ &self,
+ anon_const: &'tcx hir::AnonConst,
+ expected: Expectation<'tcx>,
+ _expr: &'tcx hir::Expr<'tcx>,
+ ) -> Ty<'tcx> {
+ let body = self.tcx.hir().body(anon_const.body);
+
+ // Create a new function context.
+ let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id);
+ crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+ let ty = fcx.check_expr_with_expectation(&body.value, expected);
+ fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
+ fcx.write_ty(anon_const.hir_id, ty);
+ ty
+ }
+
fn check_expr_repeat(
&self,
element: &'tcx hir::Expr<'tcx>,
.emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() });
}
- let error_happened = self.check_expr_struct_fields(
+ self.check_expr_struct_fields(
adt_ty,
expected,
expr.hir_id,
qpath.span(),
variant,
fields,
- base_expr.is_none(),
+ base_expr,
expr.span,
);
- if let Some(base_expr) = base_expr {
- // If check_expr_struct_fields hit an error, do not attempt to populate
- // the fields with the base_expr. This could cause us to hit errors later
- // when certain fields are assumed to exist that in fact do not.
- if !error_happened {
- self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {});
- match adt_ty.kind() {
- ty::Adt(adt, substs) if adt.is_struct() => {
- let fru_field_types = adt
- .non_enum_variant()
- .fields
- .iter()
- .map(|f| {
- self.normalize_associated_types_in(
- expr.span,
- f.ty(self.tcx, substs),
- )
- })
- .collect();
-
- self.typeck_results
- .borrow_mut()
- .fru_field_types_mut()
- .insert(expr.hir_id, fru_field_types);
- }
- _ => {
- self.tcx
- .sess
- .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
- }
- }
- }
- }
+
self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized);
adt_ty
}
span: Span,
variant: &'tcx ty::VariantDef,
ast_fields: &'tcx [hir::ExprField<'tcx>],
- check_completeness: bool,
+ base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>,
expr_span: Span,
- ) -> bool {
+ ) {
let tcx = self.tcx;
let adt_ty_hint = self
)
.emit();
}
- } else if check_completeness && !error_happened && !remaining_fields.is_empty() {
+ }
+
+ // If check_expr_struct_fields hit an error, do not attempt to populate
+ // the fields with the base_expr. This could cause us to hit errors later
+ // when certain fields are assumed to exist that in fact do not.
+ if error_happened {
+ return;
+ }
+
+ if let Some(base_expr) = base_expr {
+ // FIXME: We are currently creating two branches here in order to maintain
+ // consistency. But they should be merged as much as possible.
+ let fru_tys = if self.tcx.features().type_changing_struct_update {
+ let base_ty = self.check_expr(base_expr);
+ match adt_ty.kind() {
+ ty::Adt(adt, substs) if adt.is_struct() => {
+ match base_ty.kind() {
+ ty::Adt(base_adt, base_subs) if adt == base_adt => {
+ variant
+ .fields
+ .iter()
+ .map(|f| {
+ let fru_ty = self.normalize_associated_types_in(
+ expr_span,
+ self.field_ty(base_expr.span, f, base_subs),
+ );
+ let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
+ if let Some(_) = remaining_fields.remove(&ident) {
+ let target_ty =
+ self.field_ty(base_expr.span, f, substs);
+ let cause = self.misc(base_expr.span);
+ match self
+ .at(&cause, self.param_env)
+ .sup(target_ty, fru_ty)
+ {
+ Ok(InferOk { obligations, value: () }) => {
+ self.register_predicates(obligations)
+ }
+ // FIXME: Need better diagnostics for `FieldMisMatch` error
+ Err(_) => self
+ .report_mismatched_types(
+ &cause,
+ target_ty,
+ fru_ty,
+ FieldMisMatch(
+ variant.ident.name,
+ ident.name,
+ ),
+ )
+ .emit(),
+ }
+ }
+ fru_ty
+ })
+ .collect()
+ }
+ _ => {
+ return self
+ .report_mismatched_types(
+ &self.misc(base_expr.span),
+ adt_ty,
+ base_ty,
+ Sorts(expected_found_bool(true, adt_ty, base_ty)),
+ )
+ .emit();
+ }
+ }
+ }
+ _ => {
+ return self
+ .tcx
+ .sess
+ .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+ }
+ }
+ } else {
+ self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
+ let base_ty = self.check_expr(base_expr);
+ let same_adt = match (adt_ty.kind(), base_ty.kind()) {
+ (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true,
+ _ => false,
+ };
+ if self.tcx.sess.is_nightly_build() && same_adt {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::type_changing_struct_update,
+ base_expr.span,
+ "type changing struct updating is experimental",
+ )
+ .emit();
+ }
+ });
+ match adt_ty.kind() {
+ ty::Adt(adt, substs) if adt.is_struct() => variant
+ .fields
+ .iter()
+ .map(|f| {
+ self.normalize_associated_types_in(expr_span, f.ty(self.tcx, substs))
+ })
+ .collect(),
+ _ => {
+ return self
+ .tcx
+ .sess
+ .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+ }
+ }
+ };
+ self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr_id, fru_tys);
+ } else if kind_name != "union" && !remaining_fields.is_empty() {
let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
!field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
});
self.report_missing_fields(adt_ty, span, remaining_fields);
}
}
-
- error_happened
}
fn check_struct_fields_on_error(
#[instrument(skip(self), level = "debug")]
pub(in super::super) fn select_all_obligations_or_error(&self) {
- if let Err(errors) = self
+ let errors = self
.fulfillment_cx
.borrow_mut()
- .select_all_with_constness_or_error(&self, self.inh.constness)
- {
+ .select_all_with_constness_or_error(&self, self.inh.constness);
+
+ if !errors.is_empty() {
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
}
}
fallback_has_occurred: bool,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) {
- let result = self
+ let mut result = self
.fulfillment_cx
.borrow_mut()
.select_with_constness_where_possible(self, self.inh.constness);
- if let Err(mut errors) = result {
- mutate_fulfillment_errors(&mut errors);
- self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
+ if !result.is_empty() {
+ mutate_fulfillment_errors(&mut result);
+ self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
}
}
// we can. We don't care if some things turn
// out unconstrained or ambiguous, as we're
// just trying to get hints here.
- self.save_and_restore_in_snapshot_flag(|_| {
+ let errors = self.save_and_restore_in_snapshot_flag(|_| {
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
for obligation in ok.obligations {
fulfill.register_predicate_obligation(self, obligation);
}
fulfill.select_where_possible(self)
- })
- .map_err(|_| ())?;
+ });
+
+ if !errors.is_empty() {
+ return Err(());
+ }
}
Err(_) => return Err(()),
}
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
- let outer_def_id = tcx.closure_base_def_id(def_id);
- if outer_def_id != def_id {
- return tcx.has_typeck_results(outer_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ if typeck_root_def_id != def_id {
+ return tcx.has_typeck_results(typeck_root_def_id);
}
if let Some(def_id) = def_id.as_local() {
) -> &'tcx ty::TypeckResults<'tcx> {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
- let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
- if outer_def_id != def_id {
- return tcx.typeck(outer_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+ if typeck_root_def_id != def_id {
+ return tcx.typeck(typeck_root_def_id);
}
let id = tcx.hir().local_def_id_to_hir_id(def_id);
self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys));
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
fulfill.register_predicate_obligation(self, obligation);
- Err(match fulfill.select_where_possible(&self.infcx) {
- Err(errors) => errors,
- _ => vec![],
- })
+ Err(fulfill.select_where_possible(&self.infcx))
}
}
}
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
// All other literals result in non-reference types.
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`.
- PatKind::Lit(lt) => match self.check_expr(lt).kind() {
+ //
+ // Call `resolve_vars_if_possible` here for inline const blocks.
+ PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() {
ty::Ref(..) => AdjustMode::Pass,
_ => AdjustMode::Peel,
},
self.visit_region_obligations(body_id.hir_id);
}
+ fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) {
+ debug!("visit_inline_const(id={:?})", id);
+
+ // Save state of current function. We will restore afterwards.
+ let old_body_id = self.body_id;
+ let old_body_owner = self.body_owner;
+ let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
+
+ let body_id = body.id();
+ self.body_id = body_id.hir_id;
+ self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
+
+ self.outlives_environment.save_implied_bounds(body_id.hir_id);
+
+ self.visit_body(body);
+ self.visit_region_obligations(body_id.hir_id);
+
+ // Restore state from previous function.
+ self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
+ self.body_id = old_body_id;
+ self.body_owner = old_body_owner;
+ }
+
fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
debug!("visit_region_obligations: hir_id={:?}", hir_id);
// `visit_fn_body`. We will restore afterwards.
let old_body_id = self.body_id;
let old_body_owner = self.body_owner;
- let env_snapshot = self.outlives_environment.push_snapshot_pre_closure();
+ let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
let body = self.tcx.hir().body(body_id);
self.visit_fn_body(hir_id, body, span);
// Restore state from previous function.
- self.outlives_environment.pop_snapshot_post_closure(env_snapshot);
+ self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
self.body_id = old_body_id;
self.body_owner = old_body_owner;
}
intravisit::walk_expr(self, expr);
}
+ hir::ExprKind::ConstBlock(anon_const) => {
+ let body = self.tcx.hir().body(anon_const.body);
+ self.visit_inline_const(anon_const.hir_id, body);
+ }
+
_ => intravisit::walk_expr(self, expr),
}
}
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
- if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind {
- let body = self.fcx.tcx.hir().body(body_id);
- self.visit_body(body);
- self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+ match expr.kind {
+ hir::ExprKind::Closure(cc, _, body_id, _, _) => {
+ let body = self.fcx.tcx.hir().body(body_id);
+ self.visit_body(body);
+ self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+ }
+ hir::ExprKind::ConstBlock(anon_const) => {
+ let body = self.fcx.tcx.hir().body(anon_const.body);
+ self.visit_body(body);
+ }
+ _ => {}
}
intravisit::walk_expr(self, expr);
hir::ExprKind::Field(..) => {
self.visit_field_id(e.hir_id);
}
+ hir::ExprKind::ConstBlock(anon_const) => {
+ self.visit_node_id(e.span, anon_const.hir_id);
+
+ let body = self.tcx().hir().body(anon_const.body);
+ self.visit_body(body);
+ }
_ => {}
}
let coerced_fields = fields
.iter()
- .filter_map(|field| {
+ .filter(|field| {
let ty_a = field.ty(tcx, substs_a);
let ty_b = field.ty(tcx, substs_b);
if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
if layout.is_zst() && layout.align.abi.bytes() == 1 {
// ignore ZST fields with alignment of 1 byte
- return None;
+ return false;
}
}
))
.emit();
- return None;
+ return false;
}
}
- Some(field)
+ return true;
})
.collect::<Vec<_>>();
}
// Check that all transitive obligations are satisfied.
- if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}
fulfill_cx.register_predicate_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied.
- if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}
{
Some(parent_def_id.to_def_id())
}
-
+ Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
+ Some(tcx.typeck_root_def_id(def_id))
+ }
_ => None,
}
}
}
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
- Some(tcx.closure_base_def_id(def_id))
+ Some(tcx.typeck_root_def_id(def_id))
}
Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
}));
}
+ // provide junk type parameter defs for const blocks.
+ if let Node::AnonConst(_) = node {
+ let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
+ params.push(ty::GenericParamDef {
+ index: type_start,
+ name: Symbol::intern("<const_ty>"),
+ def_id,
+ pure_wrt_drop: false,
+ kind: ty::GenericParamDefKind::Type {
+ has_default: false,
+ object_lifetime_default: rl::Set1::Empty,
+ synthetic: None,
+ },
+ });
+ }
+ }
+
let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
ty::Generics {
Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
if anon_const.hir_id == hir_id =>
{
- tcx.typeck(def_id).node_type(anon_const.hir_id)
+ let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+ substs.as_inline_const().ty()
}
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
),
);
- if let Err(errors) = fulfill.select_all_or_error(&infcx) {
+ let errors = fulfill.select_all_or_error(&infcx);
+ if !errors.is_empty() {
tracing::debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
for error in errors {
if error.obligation.predicate == self.predicate {
}
}
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => true,
- Err(errors) => {
- infcx.report_fulfillment_errors(&errors, None, false);
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => true,
+ errors => {
+ infcx.report_fulfillment_errors(errors, None, false);
false
}
}
term_id,
cause,
);
- if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(&err, None, false);
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
error = true;
}
});
// variables. Process these constraints.
let mut fulfill_cx = FulfillmentContext::new();
fulfill_cx.register_predicate_obligations(self, result.obligations);
- if fulfill_cx.select_all_or_error(self).is_err() {
+ let errors = fulfill_cx.select_all_or_error(self);
+ if !errors.is_empty() {
self.tcx.sess.delay_span_bug(
span,
"implied_outlives_bounds failed to solve obligations from instantiation",
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !marker::Send for Rc<T> {}
+
+// Note that this negative impl isn't strictly necessary for correctness,
+// as `Rc` transitively contains a `Cell`, which is itself `!Sync`.
+// However, given how important `Rc`'s `!Sync`-ness is,
+// having an explicit negative impl is nice for documentation purposes
+// and results in nicer error messages.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !marker::Sync for Rc<T> {}
-Subproject commit 7f14f76c8ba6945c052fab77022e6e768b58e0b4
+Subproject commit b02ed04a7e915659eea6fb1607df469b84a30638
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized> Send for Cell<T> where T: Send {}
+// Note that this negative impl isn't strictly necessary for correctness,
+// as `Cell` wraps `UnsafeCell`, which is itself `!Sync`.
+// However, given how important `Cell`'s `!Sync`-ness is,
+// having an explicit negative impl is nice for documentation purposes
+// and results in nicer error messages.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Sync for Cell<T> {}
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/librustc")
+ let builder = run.builder;
+ run.path("rustc-docs").default_condition(builder.config.compiler_docs)
}
fn make_run(run: RunConfig<'_>) {
/// Builds the `rustc-docs` installer component.
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
let host = self.host;
- if !builder.config.compiler_docs {
- return None;
- }
builder.default_doc(&[]);
let mut tarball = Tarball::new(builder, "rustc-docs", &host.triple);
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
- run.krate("rustc-main").path("compiler").default_condition(builder.config.docs)
+ run.krate("rustc-main").path("compiler").default_condition(builder.config.compiler_docs)
}
fn make_run(run: RunConfig<'_>) {
})
.collect::<Vec<_>>();
- if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
- builder.info("\tskipping - compiler/librustdoc docs disabled");
- return;
- }
-
// This is the intended out directory for compiler documentation.
let out = builder.compiler_doc_out(target);
t!(fs::create_dir_all(&out));
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.krate($should_run)
+ let builder = run.builder;
+ run.krate($should_run).default_condition(builder.config.compiler_docs)
}
fn make_run(run: RunConfig<'_>) {
let compiler = builder.compiler(stage, builder.config.build);
- if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
- builder.info("\tskipping - compiler/tool docs disabled");
- return;
- }
-
// Build rustc docs so that we generate relative links.
builder.ensure(Rustc { stage, target });
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/test/rustdoc-js-std")
+ run.suite_path("src/test/rustdoc-js-std")
}
fn make_run(run: RunConfig<'_>) {
.arg(builder.doc_out(self.target))
.arg("--test-folder")
.arg(builder.src.join("src/test/rustdoc-js-std"));
+ for path in &builder.paths {
+ if let Some(p) =
+ util::is_valid_test_suite_arg(path, "src/test/rustdoc-js-std", builder)
+ {
+ if !p.ends_with(".js") {
+ eprintln!("A non-js file was given: `{}`", path.display());
+ panic!("Cannot run rustdoc-js-std tests");
+ }
+ command.arg("--test-file").arg(path);
+ }
+ }
builder.ensure(crate::doc::Std { target: self.target, stage: builder.top_stage });
builder.run(&mut command);
} else {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/test/rustdoc-js")
+ run.suite_path("src/test/rustdoc-js")
}
fn make_run(run: RunConfig<'_>) {
.arg("--tests-folder")
.arg(builder.build.src.join("src/test/rustdoc-gui"));
for path in &builder.paths {
- if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
- if name.ends_with(".goml") {
+ if let Some(p) = util::is_valid_test_suite_arg(path, "src/test/rustdoc-gui", builder) {
+ if !p.ends_with(".goml") {
+ eprintln!("A non-goml file was given: `{}`", path.display());
+ panic!("Cannot run rustdoc-gui tests");
+ }
+ if let Some(name) = path.file_name().and_then(|f| f.to_str()) {
command.arg("--file").arg(name);
}
}
// Get test-args by striping suite path
let mut test_args: Vec<&str> = paths
.iter()
- .map(|p| match p.strip_prefix(".") {
- Ok(path) => path,
- Err(_) => p,
- })
- .filter(|p| p.starts_with(suite_path))
- .filter(|p| {
- let exists = p.is_dir() || p.is_file();
- if !exists {
- if let Some(p) = p.to_str() {
- builder.info(&format!(
- "Warning: Skipping \"{}\": not a regular file or directory",
- p
- ));
- }
- }
- exists
- })
- .filter_map(|p| {
- // Since test suite paths are themselves directories, if we don't
- // specify a directory or file, we'll get an empty string here
- // (the result of the test suite directory without its suite prefix).
- // Therefore, we need to filter these out, as only the first --test-args
- // flag is respected, so providing an empty --test-args conflicts with
- // any following it.
- match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
- Some(s) if !s.is_empty() => Some(s),
- _ => None,
- }
- })
+ .filter_map(|p| util::is_valid_test_suite_arg(p, suite_path, builder))
.collect();
test_args.append(&mut builder.config.cmd.test_args());
$name:ident, $path:expr, $tool_name:expr
$(,is_external_tool = $external:expr)*
$(,is_unstable_tool = $unstable:expr)*
- $(,features = $features:expr)*
;
)+) => {
#[derive(Copy, PartialEq, Eq, Clone)]
} else {
SourceType::InTree
},
- extra_features: {
- // FIXME(#60643): avoid this lint by using `_`
- let mut _tmp = Vec::new();
- $(_tmp.extend($features);)*
- _tmp
- },
+ extra_features: vec![],
}).expect("expected to build -- essential tool")
}
}
|| target.contains("fuchsia")
|| target.contains("bpf"))
}
+
+pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>(
+ path: &'a Path,
+ suite_path: P,
+ builder: &Builder<'_>,
+) -> Option<&'a str> {
+ let suite_path = suite_path.as_ref();
+ let path = match path.strip_prefix(".") {
+ Ok(p) => p,
+ Err(_) => path,
+ };
+ if !path.starts_with(suite_path) {
+ return None;
+ }
+ let exists = path.is_dir() || path.is_file();
+ if !exists {
+ if let Some(p) = path.to_str() {
+ builder.info(&format!("Warning: Skipping \"{}\": not a regular file or directory", p));
+ }
+ return None;
+ }
+ // Since test suite paths are themselves directories, if we don't
+ // specify a directory or file, we'll get an empty string here
+ // (the result of the test suite directory without its suite prefix).
+ // Therefore, we need to filter these out, as only the first --test-args
+ // flag is respected, so providing an empty --test-args conflicts with
+ // any following it.
+ match path.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
+ Some(s) if !s.is_empty() => Some(s),
+ _ => None,
+ }
+}
--- /dev/null
+# `type_changing_struct_update`
+
+The tracking issue for this feature is: [#86555]
+
+[#86555]: https://github.com/rust-lang/rust/issues/86555
+
+------------------------
+
+This implements [RFC2528]. When turned on, you can create instances of the same struct
+that have different generic type or lifetime parameters.
+
+[RFC2528]: https://github.com/rust-lang/rfcs/blob/master/text/2528-type-changing-struct-update-syntax.md
+
+```rust
+#![allow(unused_variables, dead_code)]
+#![feature(type_changing_struct_update)]
+
+fn main () {
+ struct Foo<T, U> {
+ field1: T,
+ field2: U,
+ }
+
+ let base: Foo<String, i32> = Foo {
+ field1: String::from("hello"),
+ field2: 1234,
+ };
+ let updated: Foo<f64, i32> = Foo {
+ field1: 3.14,
+ ..base
+ };
+}
+```
| rl::Region::Free(_, node_id),
) = def
{
- if let Some(lt) = cx.lt_substs.get(&node_id).cloned() {
+ if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
return lt;
}
}
}
fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
- use rustc_hir::GenericParamCount;
let hir::Ty { hir_id: _, span, ref kind } = *hir_ty;
let qpath = match kind {
hir::TyKind::Path(qpath) => qpath,
match qpath {
hir::QPath::Resolved(None, ref path) => {
if let Res::Def(DefKind::TyParam, did) = path.res {
- if let Some(new_ty) = cx.ty_substs.get(&did).cloned() {
+ if let Some(new_ty) = cx.substs.get(&did).and_then(|p| p.as_ty()).cloned() {
return new_ty;
}
if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
}
}
- let mut alias = None;
- if let Res::Def(DefKind::TyAlias, def_id) = path.res {
- // Substitute private type aliases
- if let Some(def_id) = def_id.as_local() {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
- if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
- alias = Some(&cx.tcx.hir().expect_item(hir_id).kind);
- }
- }
- };
-
- if let Some(&hir::ItemKind::TyAlias(ref ty, ref generics)) = alias {
- let provided_params = &path.segments.last().expect("segments were empty");
- let mut ty_substs = FxHashMap::default();
- let mut lt_substs = FxHashMap::default();
- let mut ct_substs = FxHashMap::default();
- let generic_args = provided_params.args();
- {
- let mut indices: GenericParamCount = Default::default();
- for param in generics.params.iter() {
- match param.kind {
- hir::GenericParamKind::Lifetime { .. } => {
- let mut j = 0;
- let lifetime = generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Lifetime(lt) => {
- if indices.lifetimes == j {
- return Some(lt);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(lt) = lifetime.cloned() {
- let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let cleaned = if !lt.is_elided() {
- lt.clean(cx)
- } else {
- self::types::Lifetime::elided()
- };
- lt_substs.insert(lt_def_id.to_def_id(), cleaned);
- }
- indices.lifetimes += 1;
- }
- hir::GenericParamKind::Type { ref default, .. } => {
- let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let mut j = 0;
- let type_ = generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Type(ty) => {
- if indices.types == j {
- return Some(ty);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(ty) = type_ {
- ty_substs.insert(ty_param_def_id.to_def_id(), ty.clean(cx));
- } else if let Some(default) = *default {
- ty_substs
- .insert(ty_param_def_id.to_def_id(), default.clean(cx));
- }
- indices.types += 1;
- }
- hir::GenericParamKind::Const { .. } => {
- let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let mut j = 0;
- let const_ = generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Const(ct) => {
- if indices.consts == j {
- return Some(ct);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(ct) = const_ {
- ct_substs.insert(const_param_def_id.to_def_id(), ct.clean(cx));
- }
- // FIXME(const_generics_defaults)
- indices.consts += 1;
- }
- }
- }
- }
- return cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx));
+ if let Some(expanded) = maybe_expand_private_type_alias(cx, path) {
+ expanded
+ } else {
+ let path = path.clean(cx);
+ resolve_type(cx, path)
}
- let path = path.clean(cx);
- resolve_type(cx, path)
}
hir::QPath::Resolved(Some(ref qself), p) => {
// Try to normalize `<X as Y>::T` to a type
}
}
+fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_>) -> Option<Type> {
+ 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
+ } else {
+ return None;
+ };
+ let hir::ItemKind::TyAlias(ty, generics) = alias else { return None };
+
+ let provided_params = &path.segments.last().expect("segments were empty");
+ let mut substs = FxHashMap::default();
+ let generic_args = provided_params.args();
+
+ let mut indices: hir::GenericParamCount = Default::default();
+ for param in generics.params.iter() {
+ match param.kind {
+ hir::GenericParamKind::Lifetime { .. } => {
+ let mut j = 0;
+ let lifetime = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Lifetime(lt) => {
+ if indices.lifetimes == j {
+ return Some(lt);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(lt) = lifetime.cloned() {
+ let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let cleaned = if !lt.is_elided() {
+ lt.clean(cx)
+ } else {
+ self::types::Lifetime::elided()
+ };
+ substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
+ }
+ indices.lifetimes += 1;
+ }
+ hir::GenericParamKind::Type { ref default, .. } => {
+ let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let mut j = 0;
+ let type_ = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Type(ty) => {
+ if indices.types == j {
+ return Some(ty);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(ty) = type_ {
+ substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(ty.clean(cx)));
+ } else if let Some(default) = *default {
+ substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(default.clean(cx)));
+ }
+ indices.types += 1;
+ }
+ hir::GenericParamKind::Const { .. } => {
+ let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let mut j = 0;
+ let const_ = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Const(ct) => {
+ if indices.consts == j {
+ return Some(ct);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(ct) = const_ {
+ substs
+ .insert(const_param_def_id.to_def_id(), SubstParam::Constant(ct.clean(cx)));
+ }
+ // FIXME(const_generics_defaults)
+ indices.consts += 1;
+ }
+ }
+ }
+
+ Some(cx.enter_alias(substs, |cx| ty.clean(cx)))
+}
+
impl Clean<Type> for hir::Ty<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Type {
use rustc_hir::*;
}
}
}
+
+/// The type, lifetime, or constant that a private type alias's parameter should be
+/// replaced with when expanding a use of that type alias.
+///
+/// For example:
+///
+/// ```
+/// type PrivAlias<T> = Vec<T>;
+///
+/// pub fn public_fn() -> PrivAlias<i32> { vec![] }
+/// ```
+///
+/// `public_fn`'s docs will show it as returning `Vec<i32>`, since `PrivAlias` is private.
+/// [`SubstParam`] is used to record that `T` should be mapped to `i32`.
+crate enum SubstParam {
+ Type(Type),
+ Lifetime(Lifetime),
+ Constant(Constant),
+}
+
+impl SubstParam {
+ crate fn as_ty(&self) -> Option<&Type> {
+ if let Self::Type(ty) = self { Some(ty) } else { None }
+ }
+
+ crate fn as_lt(&self) -> Option<&Lifetime> {
+ if let Self::Lifetime(lt) = self { Some(lt) } else { None }
+ }
+}
| Res::NonMacroAttr(_)
| Res::Err => return res.def_id(),
Res::Def(
- TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy
- | Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator,
+ TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst
+ | InlineConst | OpaqueTy | Field | LifetimeParam | GlobalAsm | Impl | Closure
+ | Generator,
id,
) => return id,
};
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
/// the same time.
crate active_extern_traits: FxHashSet<DefId>,
- // The current set of type and lifetime substitutions,
+ // The current set of parameter substitutions,
// for expanding type aliases at the HIR level:
- /// Table `DefId` of type parameter -> substituted type
- crate ty_substs: FxHashMap<DefId, clean::Type>,
- /// Table `DefId` of lifetime parameter -> substituted lifetime
- crate lt_substs: FxHashMap<DefId, clean::Lifetime>,
- /// Table `DefId` of const parameter -> substituted const
- crate ct_substs: FxHashMap<DefId, clean::Constant>,
+ /// Table `DefId` of type, lifetime, or const parameter -> substituted type, lifetime, or const
+ crate substs: FxHashMap<DefId, clean::SubstParam>,
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
crate impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
/// Call the closure with the given parameters set as
/// the substitutions for a type alias' RHS.
- crate fn enter_alias<F, R>(
- &mut self,
- ty_substs: FxHashMap<DefId, clean::Type>,
- lt_substs: FxHashMap<DefId, clean::Lifetime>,
- ct_substs: FxHashMap<DefId, clean::Constant>,
- f: F,
- ) -> R
+ crate fn enter_alias<F, R>(&mut self, substs: FxHashMap<DefId, clean::SubstParam>, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
{
- let (old_tys, old_lts, old_cts) = (
- mem::replace(&mut self.ty_substs, ty_substs),
- mem::replace(&mut self.lt_substs, lt_substs),
- mem::replace(&mut self.ct_substs, ct_substs),
- );
+ let old_substs = mem::replace(&mut self.substs, substs);
let r = f(self);
- self.ty_substs = old_tys;
- self.lt_substs = old_lts;
- self.ct_substs = old_cts;
+ self.substs = old_substs;
r
}
// Closures' tables come from their outermost function,
// as they are part of the same "inference environment".
// This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`)
- let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
- if outer_def_id != def_id {
- return tcx.typeck(outer_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+ if typeck_root_def_id != def_id {
+ return tcx.typeck(typeck_root_def_id);
}
let hir = tcx.hir();
param_env: ParamEnv::empty(),
external_traits: Default::default(),
active_extern_traits: Default::default(),
- ty_substs: Default::default(),
- lt_substs: Default::default(),
- ct_substs: Default::default(),
+ substs: Default::default(),
impl_trait_bounds: Default::default(),
generated_synthetics: Default::default(),
auto_traits: tcx
};
if run {
debug!("running pass {}", p.pass.name);
- krate = ctxt.tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt));
+ krate = tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt));
}
}
- ctxt.sess().abort_if_errors();
+ if tcx.sess.diagnostic().has_errors_or_lint_errors() {
+ rustc_errors::FatalError.raise();
+ }
let render_options = ctxt.render_options;
let mut cache = ctxt.cache;
use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{ColorConfig, ErrorReported};
+use rustc_errors::{ColorConfig, ErrorReported, FatalError};
use rustc_hir as hir;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::intravisit;
collector
});
- compiler.session().abort_if_errors();
+ if compiler.session().diagnostic().has_errors_or_lint_errors() {
+ FatalError.raise();
+ }
let unused_extern_reports = collector.unused_extern_reports.clone();
let compiling_test_count = collector.compiling_test_count.load(Ordering::SeqCst);
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
#![feature(control_flow_enum)]
#![feature(box_syntax)]
#![feature(in_band_lifetimes)]
+#![feature(let_else)]
#![feature(nll)]
#![feature(test)]
#![feature(crate_visibility_modifier)]
// current architecture.
let resolver = core::create_resolver(queries, sess);
- if sess.has_errors() {
+ if sess.diagnostic().has_errors_or_lint_errors() {
sess.fatal("Compilation failed, aborting rustdoc");
}
| Use
| LifetimeParam
| Ctor(_, _)
- | AnonConst => {
+ | AnonConst
+ | InlineConst => {
let note = assoc_item_not_allowed(res);
if let Some(span) = sp {
diag.span_label(span, ¬e);
{
::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"],
&match () {
- () => [],
+ _args => [],
}));
};
}
as
())
{
- ()
+ _args
=>
([]
as
--- /dev/null
+#![crate_name = "foo"]
+#![no_std]
+
+// @has 'foo/fn.foo.html'
+// @has - '//*[@class="docblock"]' 'inc2 x'
+#[doc = include_str!("short-line.md")]
+pub fn foo() {}
//~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
+//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
#![deny(clippy_group)]
//~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
+//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
fn lintme() { } //~ ERROR item is named 'lintme'
//~^ WARNING lint name `test_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
+//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
#[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist`
fn hello() {
fn lintmetoo() { }
= note: `#[warn(renamed_and_removed_lints)]` on by default
warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^ help: change it to: `clippy::group`
warning: lint name `test_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:29:9
+ --> $DIR/lint-tool-test.rs:31:9
|
LL | #[allow(test_group)]
| ^^^^^^^^^^ help: change it to: `clippy::test_group`
warning: unknown lint: `this_lint_does_not_exist`
- --> $DIR/lint-tool-test.rs:33:8
+ --> $DIR/lint-tool-test.rs:36:8
|
LL | #[deny(this_lint_does_not_exist)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^ help: change it to: `clippy::test_lint`
warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^ help: change it to: `clippy::group`
warning: lint name `test_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:29:9
+ --> $DIR/lint-tool-test.rs:31:9
|
LL | #[allow(test_group)]
| ^^^^^^^^^^ help: change it to: `clippy::test_group`
| ^^^^^^^^^ help: change it to: `clippy::test_lint`
warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^ help: change it to: `clippy::group`
error: item is named 'lintme'
- --> $DIR/lint-tool-test.rs:18:1
+ --> $DIR/lint-tool-test.rs:20:1
|
LL | fn lintme() { }
| ^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^
= note: `#[deny(clippy::test_lint)]` implied by `#[deny(clippy::group)]`
error: item is named 'lintmetoo'
- --> $DIR/lint-tool-test.rs:26:5
+ --> $DIR/lint-tool-test.rs:28:5
|
LL | fn lintmetoo() { }
| ^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^
= note: `#[deny(clippy::test_group)]` implied by `#[deny(clippy::group)]`
warning: lint name `test_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:29:9
+ --> $DIR/lint-tool-test.rs:31:9
|
LL | #[allow(test_group)]
| ^^^^^^^^^^ help: change it to: `clippy::test_group`
-error: aborting due to 2 previous errors; 11 warnings emitted
+warning: lint name `test_lint` is deprecated and may not have an effect in the future.
+ --> $DIR/lint-tool-test.rs:9:23
+ |
+LL | #![cfg_attr(foo, warn(test_lint))]
+ | ^^^^^^^^^ help: change it to: `clippy::test_lint`
+
+warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
+ --> $DIR/lint-tool-test.rs:14:9
+ |
+LL | #![deny(clippy_group)]
+ | ^^^^^^^^^^^^ help: change it to: `clippy::group`
+
+warning: lint name `test_group` is deprecated and may not have an effect in the future.
+ --> $DIR/lint-tool-test.rs:31:9
+ |
+LL | #[allow(test_group)]
+ | ^^^^^^^^^^ help: change it to: `clippy::test_group`
+
+error: aborting due to 2 previous errors; 14 warnings emitted
let res =
::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""],
&match (&"u8",) {
- (arg0,) =>
- [::core::fmt::ArgumentV1::new(arg0,
+ _args =>
+ [::core::fmt::ArgumentV1::new(_args.0,
::core::fmt::Display::fmt)],
}));
res
| expected due to this
|
= note: expected unit type `()`
- found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#25t, extern "rust-call" fn(()), _#26t]]`
+ found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#22t, extern "rust-call" fn(()), _#23t]]`
help: use parentheses to call this closure
|
LL | let c1 : () = c();
| expected due to this
|
= note: expected unit type `()`
- found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#25t, extern "rust-call" fn(()), _#26t]]`
+ found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#22t, extern "rust-call" fn(()), _#23t]]`
help: use parentheses to call this closure
|
LL | let c1 : () = c();
|
LL | assert_eq!(f::<4usize>(Usizable), 20usize);
| ^^^^^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
let _ = nested::DeprecatedStruct {
//~^ ERROR use of deprecated struct `this_crate::nested::DeprecatedStruct`: text
i: 0 //~ ERROR use of deprecated field `this_crate::nested::DeprecatedStruct::i`: text
+ //~| ERROR field `i` of struct `this_crate::nested::DeprecatedStruct` is private
};
let _ = nested::DeprecatedUnitStruct; //~ ERROR use of deprecated unit struct `this_crate::nested::DeprecatedUnitStruct`: text
| ^^^^^^^^^^^^^^^^
error: use of deprecated unit struct `this_crate::nested::DeprecatedUnitStruct`: text
- --> $DIR/deprecation-lint.rs:283:25
+ --> $DIR/deprecation-lint.rs:284:25
|
LL | let _ = nested::DeprecatedUnitStruct;
| ^^^^^^^^^^^^^^^^^^^^
error: use of deprecated unit variant `this_crate::nested::Enum::DeprecatedVariant`: text
- --> $DIR/deprecation-lint.rs:285:31
+ --> $DIR/deprecation-lint.rs:286:31
|
LL | ... let _ = nested::Enum::DeprecatedVariant;
| ^^^^^^^^^^^^^^^^^
error: use of deprecated tuple struct `this_crate::nested::DeprecatedTupleStruct`: text
- --> $DIR/deprecation-lint.rs:287:25
+ --> $DIR/deprecation-lint.rs:288:25
|
LL | ... let _ = nested::DeprecatedTupleStruct (1);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:292:16
+ --> $DIR/deprecation-lint.rs:293:16
|
LL | Trait::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:294:25
+ --> $DIR/deprecation-lint.rs:295:25
|
LL | <Foo as Trait>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:296:16
+ --> $DIR/deprecation-lint.rs:297:16
|
LL | Trait::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:298:25
+ --> $DIR/deprecation-lint.rs:299:25
|
LL | ... <Foo as Trait>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar`
- --> $DIR/deprecation-lint.rs:316:13
+ --> $DIR/deprecation-lint.rs:317:13
|
LL | bar();
| ^^^
error: use of deprecated trait `this_crate::DeprecatedTrait`: text
- --> $DIR/deprecation-lint.rs:335:10
+ --> $DIR/deprecation-lint.rs:336:10
|
LL | impl DeprecatedTrait for S { }
| ^^^^^^^^^^^^^^^
error: use of deprecated trait `this_crate::DeprecatedTrait`: text
- --> $DIR/deprecation-lint.rs:337:24
+ --> $DIR/deprecation-lint.rs:338:24
|
LL | trait LocalTrait : DeprecatedTrait { }
| ^^^^^^^^^^^^^^^
error: use of deprecated struct `this_crate2::Deprecated`: text
- --> $DIR/deprecation-lint.rs:389:17
+ --> $DIR/deprecation-lint.rs:390:17
|
LL | let x = Deprecated {
| ^^^^^^^^^^
error: use of deprecated struct `this_crate2::Deprecated`: text
- --> $DIR/deprecation-lint.rs:398:13
+ --> $DIR/deprecation-lint.rs:399:13
|
LL | let Deprecated {
| ^^^^^^^^^^
error: use of deprecated struct `this_crate2::Deprecated`: text
- --> $DIR/deprecation-lint.rs:404:13
+ --> $DIR/deprecation-lint.rs:405:13
|
LL | let Deprecated
| ^^^^^^^^^^
error: use of deprecated tuple struct `this_crate2::Deprecated2`: text
- --> $DIR/deprecation-lint.rs:409:17
+ --> $DIR/deprecation-lint.rs:410:17
|
LL | let x = Deprecated2(1, 2, 3);
| ^^^^^^^^^^^
error: use of deprecated tuple struct `this_crate2::Deprecated2`: text
- --> $DIR/deprecation-lint.rs:419:13
+ --> $DIR/deprecation-lint.rs:420:13
|
LL | let Deprecated2
| ^^^^^^^^^^^
error: use of deprecated tuple struct `this_crate2::Deprecated2`: text
- --> $DIR/deprecation-lint.rs:428:13
+ --> $DIR/deprecation-lint.rs:429:13
|
LL | let Deprecated2
| ^^^^^^^^^^^
| ^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:291:13
+ --> $DIR/deprecation-lint.rs:292:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:293:16
+ --> $DIR/deprecation-lint.rs:294:16
|
LL | <Foo>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:295:13
+ --> $DIR/deprecation-lint.rs:296:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:297:16
+ --> $DIR/deprecation-lint.rs:298:16
|
LL | <Foo>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:302:13
+ --> $DIR/deprecation-lint.rs:303:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:303:13
+ --> $DIR/deprecation-lint.rs:304:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable::override2`: text
- --> $DIR/deprecation-lint.rs:362:13
+ --> $DIR/deprecation-lint.rs:363:13
|
LL | override2: 3,
| ^^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable::override2`: text
- --> $DIR/deprecation-lint.rs:366:17
+ --> $DIR/deprecation-lint.rs:367:17
|
LL | let _ = x.override2;
| ^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable::override2`: text
- --> $DIR/deprecation-lint.rs:370:13
+ --> $DIR/deprecation-lint.rs:371:13
|
LL | override2: _
| ^^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable2::2`: text
- --> $DIR/deprecation-lint.rs:378:17
+ --> $DIR/deprecation-lint.rs:379:17
|
LL | let _ = x.2;
| ^^^
error: use of deprecated field `this_crate2::Stable2::2`: text
- --> $DIR/deprecation-lint.rs:383:20
+ --> $DIR/deprecation-lint.rs:384:20
|
LL | _)
| ^
error: use of deprecated field `this_crate2::Deprecated::inherit`: text
- --> $DIR/deprecation-lint.rs:391:13
+ --> $DIR/deprecation-lint.rs:392:13
|
LL | inherit: 1,
| ^^^^^^^^^^
error: use of deprecated field `this_crate2::Deprecated::inherit`: text
- --> $DIR/deprecation-lint.rs:395:17
+ --> $DIR/deprecation-lint.rs:396:17
|
LL | let _ = x.inherit;
| ^^^^^^^^^
error: use of deprecated field `this_crate2::Deprecated::inherit`: text
- --> $DIR/deprecation-lint.rs:400:13
+ --> $DIR/deprecation-lint.rs:401:13
|
LL | inherit: _,
| ^^^^^^^^^^
error: use of deprecated field `this_crate2::Deprecated2::0`: text
- --> $DIR/deprecation-lint.rs:412:17
+ --> $DIR/deprecation-lint.rs:413:17
|
LL | let _ = x.0;
| ^^^
error: use of deprecated field `this_crate2::Deprecated2::1`: text
- --> $DIR/deprecation-lint.rs:414:17
+ --> $DIR/deprecation-lint.rs:415:17
|
LL | let _ = x.1;
| ^^^
error: use of deprecated field `this_crate2::Deprecated2::2`: text
- --> $DIR/deprecation-lint.rs:416:17
+ --> $DIR/deprecation-lint.rs:417:17
|
LL | let _ = x.2;
| ^^^
error: use of deprecated field `this_crate2::Deprecated2::0`: text
- --> $DIR/deprecation-lint.rs:421:14
+ --> $DIR/deprecation-lint.rs:422:14
|
LL | (_,
| ^
error: use of deprecated field `this_crate2::Deprecated2::1`: text
- --> $DIR/deprecation-lint.rs:423:14
+ --> $DIR/deprecation-lint.rs:424:14
|
LL | _,
| ^
error: use of deprecated field `this_crate2::Deprecated2::2`: text
- --> $DIR/deprecation-lint.rs:425:14
+ --> $DIR/deprecation-lint.rs:426:14
|
LL | _)
| ^
-error: aborting due to 122 previous errors
+error[E0451]: field `i` of struct `this_crate::nested::DeprecatedStruct` is private
+ --> $DIR/deprecation-lint.rs:280:13
+ |
+LL | i: 0
+ | ^^^^ private field
+
+error: aborting due to 123 previous errors
+For more information about this error, try `rustc --explain E0451`.
+++ /dev/null
-#[derive(Debug)]
-struct Machine<S> {
- state: S,
- common_field1: &'static str,
- common_field2: i32,
-}
-#[derive(Debug)]
-struct State1;
-#[derive(Debug, PartialEq)]
-struct State2;
-
-fn update_to_state2() {
- let m1: Machine<State1> = Machine {
- state: State1,
- common_field1: "hello",
- common_field2: 2,
- };
- let m2: Machine<State2> = Machine {
- state: State2,
- ..m1 //~ ERROR mismatched types
- };
- // FIXME: this should trigger feature gate
- assert_eq!(State2, m2.state);
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/feature-gate-type_changing_struct_update.rs:20:11
- |
-LL | ..m1
- | ^^ expected struct `State2`, found struct `State1`
- |
- = note: expected struct `Machine<State2>`
- found struct `Machine<State1>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![feature(generic_associated_types)]
+#![feature(type_alias_impl_trait)]
+
+fn main() {}
+
+trait A<'a> {
+ type B<'b>: Clone
+ // FIXME(generic_associated_types): Remove one of the below bounds
+ // https://github.com/rust-lang/rust/pull/90678#discussion_r744976085
+ where
+ 'a: 'b, Self: 'a, Self: 'b;
+
+ fn a(&'a self) -> Self::B<'a>;
+}
+
+struct C;
+
+impl<'a> A<'a> for C {
+ type B<'b> = impl Clone;
+ //~^ ERROR: lifetime bound not satisfied
+ //~| ERROR: could not find defining uses
+
+ fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope
+}
--- /dev/null
+error[E0478]: lifetime bound not satisfied
+ --> $DIR/issue-88595.rs:19:5
+ |
+LL | type B<'b> = impl Clone;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: lifetime parameter instantiated with the lifetime `'a` as defined here
+ --> $DIR/issue-88595.rs:18:6
+ |
+LL | impl<'a> A<'a> for C {
+ | ^^
+note: but lifetime parameter must outlive the lifetime `'b` as defined here
+ --> $DIR/issue-88595.rs:19:12
+ |
+LL | type B<'b> = impl Clone;
+ | ^^
+
+error: non-defining opaque type use in defining scope
+ --> $DIR/issue-88595.rs:23:23
+ |
+LL | fn a(&'a self) -> Self::B<'a> {}
+ | ^^^^^^^^^^^
+ |
+note: lifetime used multiple times
+ --> $DIR/issue-88595.rs:18:6
+ |
+LL | impl<'a> A<'a> for C {
+ | ^^
+LL | type B<'b> = impl Clone;
+ | ^^
+
+error: could not find defining uses
+ --> $DIR/issue-88595.rs:19:18
+ |
+LL | type B<'b> = impl Clone;
+ | ^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0478`.
--- /dev/null
+// edition:2018
+
+#![feature(generic_associated_types)]
+#![feature(type_alias_impl_trait)]
+
+use std::future::Future;
+
+trait MakeFut {
+ type Fut<'a> where Self: 'a;
+ fn make_fut<'a>(&'a self) -> Self::Fut<'a>;
+}
+
+impl MakeFut for &'_ mut () {
+ type Fut<'a> = impl Future<Output = ()>;
+ //~^ ERROR: the type `&mut ()` does not fulfill the required lifetime
+
+ fn make_fut<'a>(&'a self) -> Self::Fut<'a> {
+ async { () }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0477]: the type `&mut ()` does not fulfill the required lifetime
+ --> $DIR/issue-90014.rs:14:5
+ |
+LL | type Fut<'a> = impl Future<Output = ()>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: type must outlive the lifetime `'a` as defined here
+ --> $DIR/issue-90014.rs:14:14
+ |
+LL | type Fut<'a> = impl Future<Output = ()>;
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0477`.
|
LL | foo::<str>("".to_string());
| ^^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
|
LL | foo::<String>('a');
| ^^^^^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
| ^^^^^^^^^ ^^^^^^^^^^^^^ explicit generic argument not allowed
| |
| explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
//~^ ERROR defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
//~| WARNING this was previously accepted by the compiler but is being phased out
//~| ERROR `impl Trait` not allowed outside of function and method return types
+//~| ERROR no nominal type found
// Disallowed
fn in_method_generic_param_default<T = impl Debug>(_: T) {}
| ^^^^^^^^^^
error[E0562]: `impl Trait` not allowed outside of function and method return types
- --> $DIR/where-allowed.rs:240:40
+ --> $DIR/where-allowed.rs:241:40
|
LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
| ^^^^^^^^^^
error[E0562]: `impl Trait` not allowed outside of function and method return types
- --> $DIR/where-allowed.rs:246:29
+ --> $DIR/where-allowed.rs:247:29
|
LL | let _in_local_variable: impl Fn() = || {};
| ^^^^^^^^^
error[E0562]: `impl Trait` not allowed outside of function and method return types
- --> $DIR/where-allowed.rs:248:46
+ --> $DIR/where-allowed.rs:249:46
|
LL | let _in_return_in_local_variable = || -> impl Fn() { || {} };
| ^^^^^^^^^
= note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
- --> $DIR/where-allowed.rs:240:36
+ --> $DIR/where-allowed.rs:241:36
|
LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
| ^
= 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 #36887 <https://github.com/rust-lang/rust/issues/36887>
-error: aborting due to 48 previous errors
+error[E0118]: no nominal type found for inherent implementation
+ --> $DIR/where-allowed.rs:234:23
+ |
+LL | impl <T = impl Debug> T {}
+ | ^ impl requires a nominal type
+ |
+ = note: either implement a trait on it or create a newtype to wrap it instead
+
+error: aborting due to 49 previous errors
-Some errors have detailed explanations: E0562, E0658, E0666.
-For more information about an error, try `rustc --explain E0562`.
+Some errors have detailed explanations: E0118, E0562, E0658, E0666.
+For more information about an error, try `rustc --explain E0118`.
--- /dev/null
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+pub fn todo<T>() -> T {
+ const { todo!() }
+}
+
+fn main() {
+ let _: usize = const { 0 };
+}
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+impl<'a> InvariantRef<'a, ()> {
+ pub const NEW: Self = InvariantRef::new(&());
+}
+
+fn equate<T>(x: T, y: T){}
+
+fn foo<'a>() {
+ let y = ();
+ equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
+ //~^ ERROR `y` does not live long enough [E0597]
+}
+
+fn main() {
+ foo();
+}
--- /dev/null
+error[E0597]: `y` does not live long enough
+ --> $DIR/const-expr-lifetime-err.rs:24:30
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+LL | let y = ();
+LL | equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
+ | ------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `y` is borrowed for `'a`
+LL |
+LL | }
+ | - `y` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
+fn issue_78174() {
+ let foo = const { "foo" };
+ assert_eq!(foo, "foo");
+}
+
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+fn get_invariant_ref<'a>() -> InvariantRef<'a, ()> {
+ const { InvariantRef::<'a, ()>::new(&()) }
+}
+
+fn get_invariant_ref2<'a>() -> InvariantRef<'a, ()> {
+ // Try some type inference
+ const { InvariantRef::new(&()) }
+}
+
+fn main() {
+ issue_78174();
+ get_invariant_ref();
+ get_invariant_ref2();
+}
--- /dev/null
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+fn main() {
+ match 1u64 {
+ 0 => (),
+ const { 0 + 1 } => (),
+ const { 2 - 1 } ..= const { u64::MAX } => (),
+ }
+}
--- /dev/null
+// ignore-test
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+impl<'a> InvariantRef<'a, ()> {
+ pub const NEW: Self = InvariantRef::new(&());
+}
+
+fn match_invariant_ref<'a>() {
+ let y = ();
+ match InvariantRef::new(&y) {
+ //~^ ERROR `y` does not live long enough [E0597]
+ // FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without
+ // const block)
+ const { InvariantRef::<'a>::NEW } => (),
+ }
+}
+
+fn main() {
+ match_invariant_ref();
+}
--- /dev/null
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
+fn issue_78174() {
+ match "foo" {
+ const { concat!("fo", "o") } => (),
+ _ => unreachable!(),
+ }
+}
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+fn match_invariant_ref<'a>() {
+ match const { InvariantRef::<'a, _>::new(&()) } {
+ const { InvariantRef::<'a, ()>::new(&()) } => {
+ }
+ }
+}
+
+fn main() {
+ issue_78174();
+ match_invariant_ref();
+}
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "illumos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
pub unsafe fn g() {
return;
if *ptr::null() {}; //~ ERROR unreachable
+ //~| WARNING dereferencing a null pointer
}
pub fn main() {}
LL | #![deny(unreachable_code)]
| ^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+warning: dereferencing a null pointer
+ --> $DIR/issue-7246.rs:7:8
+ |
+LL | if *ptr::null() {};
+ | ^^^^^^^^^^^^ this code causes undefined behavior when executed
+ |
+ = note: `#[warn(deref_nullptr)]` on by default
+
+error: aborting due to previous error; 1 warning emitted
#![allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
#[allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
const BAR: f64 = 0.000001;
}
#[allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
fn main() {
}
| ^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:8:9
+ --> $DIR/crate_level_only_lint.rs:9:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:15:9
+ --> $DIR/crate_level_only_lint.rs:17:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:8:9
+ --> $DIR/crate_level_only_lint.rs:9:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:15:9
+ --> $DIR/crate_level_only_lint.rs:17:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
-error: aborting due to 6 previous errors
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:4:10
+ |
+LL | #![allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:9:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:17:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
//~| WARNING previously accepted by the compiler
//~| ERROR incompatible with previous
//~| WARNING previously accepted by the compiler
+//~| ERROR incompatible with previous
+//~| WARNING previously accepted by the compiler
+//~| ERROR incompatible with previous
+//~| WARNING previously accepted by the compiler
+//~| ERROR incompatible with previous
+//~| WARNING previously accepted by the compiler
fn main() {}
= 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 #81670 <https://github.com/rust-lang/rust/issues/81670>
-error: aborting due to 6 previous errors
+error: allow(nonstandard_style) incompatible with previous forbid
+ --> $DIR/forbid-group-group-2.rs:7:9
+ |
+LL | #![forbid(warnings)]
+ | -------- `forbid` level set here
+...
+LL | #[allow(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
+ |
+ = 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 #81670 <https://github.com/rust-lang/rust/issues/81670>
+
+error: allow(nonstandard_style) incompatible with previous forbid
+ --> $DIR/forbid-group-group-2.rs:7:9
+ |
+LL | #![forbid(warnings)]
+ | -------- `forbid` level set here
+...
+LL | #[allow(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
+ |
+ = 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 #81670 <https://github.com/rust-lang/rust/issues/81670>
+
+error: allow(nonstandard_style) incompatible with previous forbid
+ --> $DIR/forbid-group-group-2.rs:7:9
+ |
+LL | #![forbid(warnings)]
+ | -------- `forbid` level set here
+...
+LL | #[allow(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
+ |
+ = 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 #81670 <https://github.com/rust-lang/rust/issues/81670>
+
+error: aborting due to 9 previous errors
fn main() {
println!("{}", evil!(*(0 as *const u8)));
+ //~^ WARNING dereferencing a null pointer
}
LL | #![forbid(unsafe_code)]
| ^^^^^^^^^^^
-error: aborting due to previous error
+warning: dereferencing a null pointer
+ --> $DIR/lint-forbid-internal-unsafe.rs:15:26
+ |
+LL | println!("{}", evil!(*(0 as *const u8)));
+ | ^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+ |
+ = note: `#[warn(deref_nullptr)]` on by default
+
+error: aborting due to previous error; 1 warning emitted
#![deny(uncommon_codepoints)]
const µ: f64 = 0.000001; //~ ERROR identifier contains uncommon Unicode codepoints
+//~| WARNING should have an upper case name
fn dijkstra() {} //~ ERROR identifier contains uncommon Unicode codepoints
| ^^^^^^^^^^^^^^^^^^^
error: identifier contains uncommon Unicode codepoints
- --> $DIR/lint-uncommon-codepoints.rs:5:4
+ --> $DIR/lint-uncommon-codepoints.rs:6:4
|
LL | fn dijkstra() {}
| ^^^^^^^
error: identifier contains uncommon Unicode codepoints
- --> $DIR/lint-uncommon-codepoints.rs:8:9
+ --> $DIR/lint-uncommon-codepoints.rs:9:9
|
LL | let ㇻㇲㇳ = "rust";
| ^^^^^^
-error: aborting due to 3 previous errors
+warning: constant `µ` should have an upper case name
+ --> $DIR/lint-uncommon-codepoints.rs:3:7
+ |
+LL | const µ: f64 = 0.000001;
+ | ^ help: convert the identifier to upper case: `Μ`
+ |
+ = note: `#[warn(non_upper_case_globals)]` on by default
+
+error: aborting due to 3 previous errors; 1 warning emitted
fn a() {
// the cast is unreachable:
let x = {return} as !; //~ ERROR unreachable
+ //~| ERROR non-primitive cast
}
fn main() { }
LL | #![deny(unreachable_code)]
| ^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error[E0605]: non-primitive cast: `()` as `!`
+ --> $DIR/expr_cast.rs:9:13
+ |
+LL | let x = {return} as !;
+ | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0605`.
--- /dev/null
+// gate-test-type_changing_struct_update
+
+#[derive(Debug)]
+struct Machine<S> {
+ state: S,
+ common_field1: &'static str,
+ common_field2: i32,
+}
+#[derive(Debug)]
+struct State1;
+#[derive(Debug, PartialEq)]
+struct State2;
+
+fn update_to_state2() {
+ let m1: Machine<State1> = Machine {
+ state: State1,
+ common_field1: "hello",
+ common_field2: 2,
+ };
+ let m2: Machine<State2> = Machine {
+ state: State2,
+ ..m1
+ //~^ ERROR type changing struct updating is experimental [E0658]
+ //~| ERROR mismatched types [E0308]
+ };
+ assert_eq!(State2, m2.state);
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: type changing struct updating is experimental
+ --> $DIR/feature-gate.rs:22:11
+ |
+LL | ..m1
+ | ^^
+ |
+ = note: see issue #86555 <https://github.com/rust-lang/rust/issues/86555> for more information
+ = help: add `#![feature(type_changing_struct_update)]` to the crate attributes to enable
+
+error[E0308]: mismatched types
+ --> $DIR/feature-gate.rs:22:11
+ |
+LL | ..m1
+ | ^^ expected struct `State2`, found struct `State1`
+ |
+ = note: expected struct `Machine<State2>`
+ found struct `Machine<State1>`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+#![feature(type_changing_struct_update)]
+#![allow(incomplete_features)]
+
+#[derive(Clone)]
+struct Machine<'a, S> {
+ state: S,
+ lt_str: &'a str,
+ common_field: i32,
+}
+
+#[derive(Clone)]
+struct State1;
+#[derive(Clone)]
+struct State2;
+
+fn update_to_state2() {
+ let s = String::from("hello");
+ let m1: Machine<State1> = Machine {
+ state: State1,
+ lt_str: &s,
+ //~^ ERROR `s` does not live long enough [E0597]
+ // FIXME: The error here actually comes from line 34. The
+ // span of the error message should be corrected to line 34
+ common_field: 2,
+ };
+ // update lifetime
+ let m3: Machine<'static, State1> = Machine {
+ lt_str: "hello, too",
+ ..m1.clone()
+ };
+ // update lifetime and type
+ let m4: Machine<'static, State2> = Machine {
+ state: State2,
+ lt_str: "hello, again",
+ ..m1.clone()
+ };
+ // updating to `static should fail.
+ let m2: Machine<'static, State1> = Machine {
+ ..m1
+ };
+}
+
+fn main() {}
--- /dev/null
+error[E0597]: `s` does not live long enough
+ --> $DIR/lifetime-update.rs:20:17
+ |
+LL | lt_str: &s,
+ | ^^ borrowed value does not live long enough
+...
+LL | let m2: Machine<'static, State1> = Machine {
+ | ------------------------ type annotation requires that `s` is borrowed for `'static`
+...
+LL | }
+ | - `s` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+#![feature(type_changing_struct_update)]
+#![allow(incomplete_features)]
+
+struct Machine<'a, S, M> {
+ state: S,
+ message: M,
+ lt_str: &'a str,
+ common_field: i32,
+}
+
+struct State1;
+struct State2;
+
+struct Message1;
+struct Message2;
+
+fn update() {
+ let m1: Machine<State1, Message1> = Machine {
+ state: State1,
+ message: Message1,
+ lt_str: "hello",
+ common_field: 2,
+ };
+ // single type update
+ let m2: Machine<State2, Message1> = Machine {
+ state: State2,
+ ..m1
+ };
+ // multiple type update
+ let m3: Machine<State2, Message2> = Machine {
+ state: State2,
+ message: Message2,
+ ..m1
+ };
+}
+
+fn fail_update() {
+ let m1: Machine<f64, f64> = Machine {
+ state: 3.2,
+ message: 6.4,
+ lt_str: "hello",
+ common_field: 2,
+ };
+ // single type update fail
+ let m2: Machine<i32, f64> = Machine {
+ ..m1
+ //~^ ERROR mismatched types [E0308]
+ };
+ // multiple type update fail
+ let m3 = Machine::<i32, i32> {
+ ..m1
+ //~^ ERROR mismatched types [E0308]
+ //~| ERROR mismatched types [E0308]
+ };
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/type-generic-update.rs:46:11
+ |
+LL | ..m1
+ | ^^ field type mismatch: Machine.state
+ |
+ = note: expected type `i32`
+ found type `f64`
+
+error[E0308]: mismatched types
+ --> $DIR/type-generic-update.rs:51:11
+ |
+LL | ..m1
+ | ^^ field type mismatch: Machine.state
+ |
+ = note: expected type `i32`
+ found type `f64`
+
+error[E0308]: mismatched types
+ --> $DIR/type-generic-update.rs:51:11
+ |
+LL | ..m1
+ | ^^ field type mismatch: Machine.message
+ |
+ = note: expected type `i32`
+ found type `f64`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
#![feature(staged_api)]
+//~^ ERROR module has missing stability attribute
-#[stable(feature = "x", since = "1")]
+#[stable(feature = "a", since = "1")]
struct StableType;
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "b", issue = "none")]
struct UnstableType;
-#[stable(feature = "x", since = "1")]
+#[stable(feature = "c", since = "1")]
trait StableTrait {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "d", issue = "none")]
trait UnstableTrait {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "e", issue = "none")]
impl UnstableTrait for UnstableType {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "f", issue = "none")]
impl StableTrait for UnstableType {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "g", issue = "none")]
impl UnstableTrait for StableType {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "h", issue = "none")]
//~^ ERROR an `#[unstable]` annotation here has no effect [ineffective_unstable_trait_impl]
impl StableTrait for StableType {}
error: an `#[unstable]` annotation here has no effect
- --> $DIR/stability-attribute-trait-impl.rs:24:1
+ --> $DIR/stability-attribute-trait-impl.rs:25:1
|
-LL | #[unstable(feature = "x", issue = "none")]
+LL | #[unstable(feature = "h", issue = "none")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[deny(ineffective_unstable_trait_impl)]` on by default
= note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
-error: aborting due to previous error
+error: module has missing stability attribute
+ --> $DIR/stability-attribute-trait-impl.rs:1:1
+ |
+LL | / #![feature(staged_api)]
+LL | |
+LL | |
+LL | | #[stable(feature = "a", since = "1")]
+... |
+LL | |
+LL | | fn main() {}
+ | |____________^
+
+error: aborting due to 2 previous errors
static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
+//~| ERROR undefined behavior to use this value
+//~| WARN: type `Void` does not permit zero-initialization
static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
+//~| ERROR undefined behavior to use this value
+//~| WARN: type `Void` does not permit zero-initialization
fn main() {}
= note: uninhabited statics cannot be initialized, and any access would be an immediate error
error: static of uninhabited type
- --> $DIR/uninhabited-static.rs:14:1
+ --> $DIR/uninhabited-static.rs:16:1
|
LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840>
= note: uninhabited statics cannot be initialized, and any access would be an immediate error
-error: aborting due to 4 previous errors
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/uninhabited-static.rs:12:1
+ |
+LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 0, align: 1) {}
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/uninhabited-static.rs:16:1
+ |
+LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 0, align: 1) {}
+
+warning: the type `Void` does not permit zero-initialization
+ --> $DIR/uninhabited-static.rs:12:31
+ |
+LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | this code causes undefined behavior when executed
+ | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+ |
+ = note: `#[warn(invalid_value)]` on by default
+ = note: enums with no variants have no valid value
+
+warning: the type `Void` does not permit zero-initialization
+ --> $DIR/uninhabited-static.rs:16:32
+ |
+LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | this code causes undefined behavior when executed
+ | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+ |
+ = note: enums with no variants have no valid value
+
+error: aborting due to 6 previous errors; 2 warnings emitted
+For more information about this error, try `rustc --explain E0080`.
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "illumos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
|
LL | func::<u8>(42);
| ^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
--> $DIR/synthetic-param.rs:23:17
|
LL | Foo::func::<u8>(42);
| ^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
--> $DIR/synthetic-param.rs:26:23
|
LL | Bar::<i8>::func::<u8>(42);
| ^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to 3 previous errors
type V = u8;
fn f() -> Self::V { 0 }
//~^ ERROR ambiguous associated item
+ //~| ERROR ambiguous associated item
//~| WARN this was previously accepted
+ //~| WARN this was previously accepted
+ //~| HELP use fully-qualified syntax
//~| HELP use fully-qualified syntax
}
LL | type V;
| ^^^^^^^
-error: aborting due to previous error
+error: ambiguous associated item
+ --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:32:15
+ |
+LL | fn f() -> Self::V { 0 }
+ | ^^^^^^^ help: use fully-qualified syntax: `<E as Tr>::V`
+ |
+ = 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 #57644 <https://github.com/rust-lang/rust/issues/57644>
+note: `V` could refer to the variant defined here
+ --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:22:5
+ |
+LL | V
+ | ^
+note: `V` could also refer to the associated type defined here
+ --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:26:5
+ |
+LL | type V;
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
-#![feature(use_nested_groups)]
#![allow(dead_code)]
#![deny(unused_imports)]
error: unused imports: `*`, `Foo`, `baz::{}`, `foobar::*`
- --> $DIR/use-nested-groups-unused-imports.rs:16:11
+ --> $DIR/use-nested-groups-unused-imports.rs:15:11
|
LL | use foo::{Foo, bar::{baz::{}, foobar::*}, *};
| ^^^ ^^^^^^^ ^^^^^^^^^ ^
|
note: the lint level is defined here
- --> $DIR/use-nested-groups-unused-imports.rs:3:9
+ --> $DIR/use-nested-groups-unused-imports.rs:2:9
|
LL | #![deny(unused_imports)]
| ^^^^^^^^^^^^^^
error: unused import: `*`
- --> $DIR/use-nested-groups-unused-imports.rs:18:24
+ --> $DIR/use-nested-groups-unused-imports.rs:17:24
|
LL | use foo::bar::baz::{*, *};
| ^
error: unused import: `foo::{}`
- --> $DIR/use-nested-groups-unused-imports.rs:20:5
+ --> $DIR/use-nested-groups-unused-imports.rs:19:5
|
LL | use foo::{};
| ^^^^^^^
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "illumos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
- target_os = "vxworks",
- target_os = "solaris"))]
+ target_os = "solaris",
+ target_os = "vxworks"))]
pub fn main() { }
-Subproject commit 94ca096afbf25f670e76e07dca754fcfe27134be
+Subproject commit 2e2a16e983f597da62bc132eb191bc3276d4b1bb
if is_future {
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
let span = decl.output.span();
- let send_result = cx.tcx.infer_ctxt().enter(|infcx| {
+ let send_errors = cx.tcx.infer_ctxt().enter(|infcx| {
let cause = traits::ObligationCause::misc(span, hir_id);
let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause);
fulfillment_cx.select_all_or_error(&infcx)
});
- if let Err(send_errors) = send_result {
+ if !send_errors.is_empty() {
span_lint_and_then(
cx,
FUTURE_NOT_SEND,
PatKind::Path(path) => {
#[allow(clippy::match_same_arms)]
let id = match cx.qpath_res(path, pat.hir_id) {
- Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return,
+ Res::Def(
+ DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
+ _,
+ ) => return,
Res::Def(_, id) => id,
_ => return,
};
#![deny(clippy::missing_docs_in_private_items)]
use crate::ty::is_type_diagnostic_item;
-use crate::{is_expn_of, last_path_segment, match_def_path, path_to_local_id, paths};
+use crate::{is_expn_of, last_path_segment, match_def_path, paths};
use if_chain::if_chain;
use rustc_ast::ast::{self, LitKind};
use rustc_hir as hir;
use rustc_hir::{
- Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, PatKind, QPath, StmtKind, UnOp,
+ Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp,
};
use rustc_lint::LateContext;
use rustc_span::{sym, symbol, ExpnKind, Span, Symbol};
pub format_string_parts: &'tcx [Expr<'tcx>],
/// Symbols corresponding to [`Self::format_string_parts`]
pub format_string_symbols: Vec<Symbol>,
- /// Match arm patterns, the `arg0`, etc. from the next field `args`
- pub arg_names: &'tcx [Pat<'tcx>],
/// Expressions like `ArgumentV1::new(arg0, Debug::fmt)`
pub args: &'tcx [Expr<'tcx>],
/// The final argument passed to `Arguments::new_v1_formatted`, if applicable
_ => None,
})
.collect();
- if let PatKind::Tuple(arg_names, None) = arm.pat.kind;
if let ExprKind::Array(args) = arm.body.kind;
then {
Some(FormatArgsExpn {
value_args,
format_string_parts,
format_string_symbols,
- arg_names,
args,
fmt_expr,
})
if let Ok(i) = usize::try_from(position);
let arg = &self.args[i];
if let ExprKind::Call(_, [arg_name, _]) = arg.kind;
- if let Some(j) = self
- .arg_names
- .iter()
- .position(|pat| path_to_local_id(arg_name, pat.hir_id));
+ if let ExprKind::Field(_, j) = arg_name.kind;
+ if let Ok(j) = j.name.as_str().parse::<usize>();
then {
Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) })
} else {
+#![allow(clippy::excessive_precision)]
#[deny(clippy::unreadable_literal)]
fn allow_inconsistent_digit_grouping() {
error: digits grouped inconsistently by underscores
- --> $DIR/test.rs:18:18
+ --> $DIR/test.rs:19:18
|
LL | let _fail1 = 100_200_300.123456789;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider: `100_200_300.123_456_789`
};
}
+#[derive(Copy, Clone)]
pub struct S;
impl S {
pub fn f(&self) -> &Self {
m!(self)
}
- pub fn f_mut(&self) -> &Self {
+ #[allow(unused_mut)] // mut will be unused, once the macro is fixed
+ pub fn f_mut(mut self) -> Self {
m_mut!(self)
}
}
};
}
+#[derive(Copy, Clone)]
pub struct S;
impl S {
pub fn f(&self) -> &Self {
m!(self)
}
- pub fn f_mut(&self) -> &Self {
+ #[allow(unused_mut)] // mut will be unused, once the macro is fixed
+ pub fn f_mut(mut self) -> Self {
m_mut!(self)
}
}
#[warn(clippy::double_neg)]
+#[allow(clippy::no_effect)]
fn main() {
let x = 1;
-x;
error: `--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op
- --> $DIR/double_neg.rs:6:5
+ --> $DIR/double_neg.rs:7:5
|
LL | --x;
| ^^^
#![warn(clippy::fn_params_excessive_bools)]
+#![allow(clippy::too_many_arguments)]
extern "C" {
fn f(_: bool, _: bool, _: bool, _: bool);
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:17:1
+ --> $DIR/fn_params_excessive_bools.rs:18:1
|
LL | fn g(_: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:20:1
+ --> $DIR/fn_params_excessive_bools.rs:21:1
|
LL | fn t(_: S, _: S, _: Box<S>, _: Vec<u32>, _: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:24:5
+ --> $DIR/fn_params_excessive_bools.rs:25:5
|
LL | fn f(_: bool, _: bool, _: bool, _: bool);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:29:5
+ --> $DIR/fn_params_excessive_bools.rs:30:5
|
LL | fn f(&self, _: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:41:5
+ --> $DIR/fn_params_excessive_bools.rs:42:5
|
LL | / fn n(_: bool, _: u32, _: bool, _: Box<u32>, _: bool, _: bool) {
LL | | fn nn(_: bool, _: bool, _: bool, _: bool) {}
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:42:9
+ --> $DIR/fn_params_excessive_bools.rs:43:9
|
LL | fn nn(_: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#![allow(unused_assignments)]
#![allow(clippy::if_same_then_else)]
#![allow(clippy::deref_addrof)]
+#![allow(clippy::nonminimal_bool)]
fn foo() -> bool {
true
error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)`
- --> $DIR/formatting.rs:15:6
+ --> $DIR/formatting.rs:16:6
|
LL | a =- 35;
| ^^^^
= note: to remove this lint, use either `-=` or `= -`
error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
- --> $DIR/formatting.rs:16:6
+ --> $DIR/formatting.rs:17:6
|
LL | a =* &191;
| ^^^^
= note: to remove this lint, use either `*=` or `= *`
error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)`
- --> $DIR/formatting.rs:19:6
+ --> $DIR/formatting.rs:20:6
|
LL | b =! false;
| ^^^^
= note: to remove this lint, use either `!=` or `= !`
error: possibly missing a comma here
- --> $DIR/formatting.rs:28:19
+ --> $DIR/formatting.rs:29:19
|
LL | -1, -2, -3 // <= no comma here
| ^
= note: to remove this lint, add a comma or write the expr in a single line
error: possibly missing a comma here
- --> $DIR/formatting.rs:32:19
+ --> $DIR/formatting.rs:33:19
|
LL | -1, -2, -3 // <= no comma here
| ^
= note: to remove this lint, add a comma or write the expr in a single line
error: possibly missing a comma here
- --> $DIR/formatting.rs:69:11
+ --> $DIR/formatting.rs:70:11
|
LL | -1
| ^
#![warn(clippy::zero_prefixed_literal)]
#![warn(clippy::unseparated_literal_suffix)]
#![warn(clippy::separated_literal_suffix)]
-#![allow(dead_code)]
+#![allow(dead_code, overflowing_literals)]
fn main() {
let ok1 = 0xABCD;
+#![allow(clippy::too_many_arguments, clippy::diverging_sub_expression)]
#![warn(clippy::many_single_char_names)]
fn bla() {
error: 5 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:4:9
+ --> $DIR/many_single_char_names.rs:5:9
|
LL | let a: i32;
| ^
= note: `-D clippy::many-single-char-names` implied by `-D warnings`
error: 6 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:4:9
+ --> $DIR/many_single_char_names.rs:5:9
|
LL | let a: i32;
| ^
| ^
error: 5 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:4:9
+ --> $DIR/many_single_char_names.rs:5:9
|
LL | let a: i32;
| ^
| ^
error: 8 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:29:13
+ --> $DIR/many_single_char_names.rs:30:13
|
LL | fn bindings(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) {}
| ^ ^ ^ ^ ^ ^ ^ ^
error: 8 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:32:10
+ --> $DIR/many_single_char_names.rs:33:10
|
LL | let (a, b, c, d, e, f, g, h): (bool, bool, bool, bool, bool, bool, bool, bool) = unimplemented!();
| ^ ^ ^ ^ ^ ^ ^ ^
#![allow(
dead_code,
unused_variables,
+ overflowing_literals,
clippy::excessive_precision,
clippy::inconsistent_digit_grouping
)]
let fail25 = 1E2_f32;
let fail26 = 43E7_f64;
let fail27 = 243E17_f32;
- #[allow(overflowing_literals)]
let fail28 = 241_251_235E723_f64;
let ok29 = 42279.911_32;
#![allow(
dead_code,
unused_variables,
+ overflowing_literals,
clippy::excessive_precision,
clippy::inconsistent_digit_grouping
)]
let fail25 = 1E2_32;
let fail26 = 43E7_64;
let fail27 = 243E17_32;
- #[allow(overflowing_literals)]
let fail28 = 241251235E723_64;
let ok29 = 42279.911_32;
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:11:18
+ --> $DIR/mistyped_literal_suffix.rs:12:18
|
LL | let fail14 = 2_32;
| ^^^^ help: did you mean to write: `2_i32`
= note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:12:18
+ --> $DIR/mistyped_literal_suffix.rs:13:18
|
LL | let fail15 = 4_64;
| ^^^^ help: did you mean to write: `4_i64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:13:18
+ --> $DIR/mistyped_literal_suffix.rs:14:18
|
LL | let fail16 = 7_8; //
| ^^^ help: did you mean to write: `7_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:14:18
+ --> $DIR/mistyped_literal_suffix.rs:15:18
|
LL | let fail17 = 23_16; //
| ^^^^^ help: did you mean to write: `23_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:17:18
+ --> $DIR/mistyped_literal_suffix.rs:18:18
|
LL | let fail20 = 2__8; //
| ^^^^ help: did you mean to write: `2_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:18:18
+ --> $DIR/mistyped_literal_suffix.rs:19:18
|
LL | let fail21 = 4___16; //
| ^^^^^^ help: did you mean to write: `4_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:21:18
+ --> $DIR/mistyped_literal_suffix.rs:22:18
|
LL | let fail25 = 1E2_32;
| ^^^^^^ help: did you mean to write: `1E2_f32`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:22:18
+ --> $DIR/mistyped_literal_suffix.rs:23:18
|
LL | let fail26 = 43E7_64;
| ^^^^^^^ help: did you mean to write: `43E7_f64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:23:18
+ --> $DIR/mistyped_literal_suffix.rs:24:18
|
LL | let fail27 = 243E17_32;
| ^^^^^^^^^ help: did you mean to write: `243E17_f32`
// fn call_with_mut_self<'life0>(self: &'life0 mut Self) {}
#[rename_my_lifetimes]
impl T2 for S2 {
+ #[allow(clippy::needless_lifetimes)]
fn call_with_mut_self(self: &mut Self) {}
}
}
error: the type of the `self` parameter does not need to be arbitrary
- --> $DIR/needless_arbitrary_self_type_unfixable.rs:41:31
+ --> $DIR/needless_arbitrary_self_type_unfixable.rs:42:31
|
LL | fn call_with_mut_self(self: &mut Self) {}
| ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'_ mut self`
};
}
+#[allow(clippy::nonminimal_bool)]
fn main() {
let mut i = 1;
while i < 10 {
error: this `else` block is redundant
- --> $DIR/needless_continue.rs:28:16
+ --> $DIR/needless_continue.rs:29:16
|
LL | } else {
| ________________^
}
error: there is no need for an explicit `else` block for this `if` expression
- --> $DIR/needless_continue.rs:43:9
+ --> $DIR/needless_continue.rs:44:9
|
LL | / if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
LL | | continue;
}
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:56:9
+ --> $DIR/needless_continue.rs:57:9
|
LL | continue; // should lint here
| ^^^^^^^^^
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:63:9
+ --> $DIR/needless_continue.rs:64:9
|
LL | continue; // should lint here
| ^^^^^^^^^
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:70:9
+ --> $DIR/needless_continue.rs:71:9
|
LL | continue // should lint here
| ^^^^^^^^
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:78:9
+ --> $DIR/needless_continue.rs:79:9
|
LL | continue // should lint here
| ^^^^^^^^
= help: consider dropping the `continue` expression
error: this `else` block is redundant
- --> $DIR/needless_continue.rs:128:24
+ --> $DIR/needless_continue.rs:129:24
|
LL | } else {
| ________________________^
}
error: there is no need for an explicit `else` block for this `if` expression
- --> $DIR/needless_continue.rs:134:17
+ --> $DIR/needless_continue.rs:135:17
|
LL | / if condition() {
LL | | continue; // should lint here
#![warn(clippy::all)]
-#![allow(unused, clippy::println_empty_string)]
+#![allow(unused, clippy::println_empty_string, non_snake_case)]
#[derive(Clone, Debug)]
enum MaybeInst {
impl MaybeInst {
fn fill(&mut self) {
+ #[allow(non_fmt_panics)]
let filled = match *self {
MaybeInst::Split1(goto1) => panic!("1"),
MaybeInst::Split2(goto2) => panic!("2"),
}
fn issue3078() {
+ #[allow(clippy::single_match)]
match "a" {
stringify!(a) => {},
_ => {},
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:27:9
+ --> $DIR/non_expressive_names.rs:28:9
|
LL | let _1 = 1; //~ERROR Consider a more descriptive name
| ^^
= note: `-D clippy::just-underscores-and-digits` implied by `-D warnings`
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:28:9
+ --> $DIR/non_expressive_names.rs:29:9
|
LL | let ____1 = 1; //~ERROR Consider a more descriptive name
| ^^^^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:29:9
+ --> $DIR/non_expressive_names.rs:30:9
|
LL | let __1___2 = 12; //~ERROR Consider a more descriptive name
| ^^^^^^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:49:13
+ --> $DIR/non_expressive_names.rs:51:13
|
LL | let _1 = 1;
| ^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:50:13
+ --> $DIR/non_expressive_names.rs:52:13
|
LL | let ____1 = 1;
| ^^^^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:51:13
+ --> $DIR/non_expressive_names.rs:53:13
|
LL | let __1___2 = 12;
| ^^^^^^^
#[allow(clippy::needless_return)]
(|| return 2)();
(|| -> Option<i32> { None? })();
+ #[allow(clippy::try_err)]
(|| -> Result<i32, i32> { Err(2)? })();
}
#![warn(clippy::redundant_else)]
-#![allow(clippy::needless_return)]
+#![allow(clippy::needless_return, clippy::if_same_then_else)]
fn main() {
loop {
1
};
// assign
- let a;
+ let mut a;
a = if foo() {
return;
} else {
#![warn(clippy::similar_names)]
-#![allow(unused, clippy::println_empty_string)]
+#![allow(
+ unused,
+ clippy::println_empty_string,
+ clippy::empty_loop,
+ clippy::diverging_sub_expression
+)]
struct Foo {
apple: i32,
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:15:9
+ --> $DIR/similar_names.rs:20:9
|
LL | let bpple: i32;
| ^^^^^
|
= note: `-D clippy::similar-names` implied by `-D warnings`
note: existing binding defined here
- --> $DIR/similar_names.rs:13:9
+ --> $DIR/similar_names.rs:18:9
|
LL | let apple: i32;
| ^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:17:9
+ --> $DIR/similar_names.rs:22:9
|
LL | let cpple: i32;
| ^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:13:9
+ --> $DIR/similar_names.rs:18:9
|
LL | let apple: i32;
| ^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:41:9
+ --> $DIR/similar_names.rs:46:9
|
LL | let bluby: i32;
| ^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:40:9
+ --> $DIR/similar_names.rs:45:9
|
LL | let blubx: i32;
| ^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:45:9
+ --> $DIR/similar_names.rs:50:9
|
LL | let coke: i32;
| ^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:43:9
+ --> $DIR/similar_names.rs:48:9
|
LL | let cake: i32;
| ^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:63:9
+ --> $DIR/similar_names.rs:68:9
|
LL | let xyzeabc: i32;
| ^^^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:61:9
+ --> $DIR/similar_names.rs:66:9
|
LL | let xyz1abc: i32;
| ^^^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:67:9
+ --> $DIR/similar_names.rs:72:9
|
LL | let parsee: i32;
| ^^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:65:9
+ --> $DIR/similar_names.rs:70:9
|
LL | let parser: i32;
| ^^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:88:16
+ --> $DIR/similar_names.rs:93:16
|
LL | bpple: sprang,
| ^^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:87:16
+ --> $DIR/similar_names.rs:92:16
|
LL | apple: spring,
| ^^^^^^
// aux-build:proc_macro_suspicious_else_formatting.rs
#![warn(clippy::suspicious_else_formatting)]
+#![allow(clippy::if_same_then_else)]
extern crate proc_macro_suspicious_else_formatting;
use proc_macro_suspicious_else_formatting::DeriveBadSpan;
error: this looks like an `else {..}` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:16:6
+ --> $DIR/suspicious_else_formatting.rs:17:6
|
LL | } {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the next block
error: this looks like an `else if` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:20:6
+ --> $DIR/suspicious_else_formatting.rs:21:6
|
LL | } if foo() {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
error: this looks like an `else if` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:27:10
+ --> $DIR/suspicious_else_formatting.rs:28:10
|
LL | } if foo() {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
error: this looks like an `else if` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:35:10
+ --> $DIR/suspicious_else_formatting.rs:36:10
|
LL | } if foo() {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
error: this is an `else {..}` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:44:6
+ --> $DIR/suspicious_else_formatting.rs:45:6
|
LL | } else
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
error: this is an `else if` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:56:6
+ --> $DIR/suspicious_else_formatting.rs:57:6
|
LL | } else
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
error: this is an `else if` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:61:6
+ --> $DIR/suspicious_else_formatting.rs:62:6
|
LL | }
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
error: this is an `else {..}` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:88:6
+ --> $DIR/suspicious_else_formatting.rs:89:6
|
LL | }
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
error: this is an `else {..}` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:96:6
+ --> $DIR/suspicious_else_formatting.rs:97:6
|
LL | }
| ______^
#![warn(clippy::suspicious_operation_groupings)]
+#![allow(clippy::eq_op)]
struct Vec3 {
x: f64,
}
}
-fn inside_an_if_statement(s1: &S, s2: &S) {
+fn inside_an_if_statement(s1: &mut S, s2: &S) {
// There's no `s1.b`
if s1.a < s2.a && s1.a < s2.b {
s1.c = s2.c;
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:14:9
+ --> $DIR/suspicious_operation_groupings.rs:15:9
|
LL | self.x == other.y && self.y == other.y && self.z == other.z
| ^^^^^^^^^^^^^^^^^ help: did you mean: `self.x == other.x`
= note: `-D clippy::suspicious-operation-groupings` implied by `-D warnings`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:27:20
+ --> $DIR/suspicious_operation_groupings.rs:28:20
|
LL | s1.a < s2.a && s1.a < s2.b
| ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:75:33
+ --> $DIR/suspicious_operation_groupings.rs:76:33
|
LL | s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:80:19
+ --> $DIR/suspicious_operation_groupings.rs:81:19
|
LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:80:19
+ --> $DIR/suspicious_operation_groupings.rs:81:19
|
LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:85:19
+ --> $DIR/suspicious_operation_groupings.rs:86:19
|
LL | s1.a * s2.a + s2.b * s2.b + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:90:19
+ --> $DIR/suspicious_operation_groupings.rs:91:19
|
LL | s1.a * s2.a + s1.b * s1.b + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:95:5
+ --> $DIR/suspicious_operation_groupings.rs:96:5
|
LL | s1.a * s1.a + s1.b * s2.b + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.a * s2.a`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:100:33
+ --> $DIR/suspicious_operation_groupings.rs:101:33
|
LL | s1.a * s2.a + s1.b * s2.b + s1.c * s1.c
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:113:20
+ --> $DIR/suspicious_operation_groupings.rs:114:20
|
LL | (s1.a * s2.a + s1.b * s1.b)
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:118:34
+ --> $DIR/suspicious_operation_groupings.rs:119:34
|
LL | (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d)
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:123:38
+ --> $DIR/suspicious_operation_groupings.rs:124:38
|
LL | (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:128:39
+ --> $DIR/suspicious_operation_groupings.rs:129:39
|
LL | ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:133:42
+ --> $DIR/suspicious_operation_groupings.rs:134:42
|
LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d)))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:133:42
+ --> $DIR/suspicious_operation_groupings.rs:134:42
|
LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d)))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:138:40
+ --> $DIR/suspicious_operation_groupings.rs:139:40
|
LL | (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:143:40
+ --> $DIR/suspicious_operation_groupings.rs:144:40
|
LL | ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:148:20
+ --> $DIR/suspicious_operation_groupings.rs:149:20
|
LL | (s1.a * s2.a + s2.b * s2.b) / 2
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:153:35
+ --> $DIR/suspicious_operation_groupings.rs:154:35
|
LL | i32::swap_bytes(s1.a * s2.a + s2.b * s2.b)
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:158:29
+ --> $DIR/suspicious_operation_groupings.rs:159:29
|
LL | s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d
| ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:163:17
+ --> $DIR/suspicious_operation_groupings.rs:164:17
|
LL | s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d
| ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:172:77
+ --> $DIR/suspicious_operation_groupings.rs:173:77
|
LL | (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `(n1.inner.2).0 == (n2.inner.2).0`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:186:25
+ --> $DIR/suspicious_operation_groupings.rs:187:25
|
LL | s1.a <= s2.a && s1.a <= s2.b
| ^^^^^^^^^^^^ help: did you mean: `s1.b <= s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:192:23
+ --> $DIR/suspicious_operation_groupings.rs:193:23
|
LL | if s1.a < s2.a && s1.a < s2.b {
| ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:199:48
+ --> $DIR/suspicious_operation_groupings.rs:200:48
|
LL | -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d)))
| ^^^^^^^^^^^^^ help: did you mean: `-s1.c * -s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:204:27
+ --> $DIR/suspicious_operation_groupings.rs:205:27
|
LL | -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a })
| ^^^^^^^^^^^^^ help: did you mean: `-s1.b < -s2.b`
-Subproject commit 04f03a360ab8fef3d9c0ff84de2d39b8a196c717
+Subproject commit 2c0f433fd2e838ae181f87019b6f1fefe33c6f54
console.log(" --doc-folder [PATH] : location of the generated doc folder");
console.log(" --help : show this message then quit");
console.log(" --crate-name [STRING] : crate name to be used");
- console.log(" --test-file [PATH] : location of the JS test file");
+ console.log(" --test-file [PATHs] : location of the JS test files (can be called " +
+ "multiple times)");
console.log(" --test-folder [PATH] : location of the JS tests folder");
console.log(" --resource-suffix [STRING] : suffix to refer to the correct files");
}
"resource_suffix": "",
"doc_folder": "",
"test_folder": "",
- "test_file": "",
+ "test_file": [],
};
var correspondences = {
"--resource-suffix": "resource_suffix",
console.log("Missing argument after `" + args[i - 1] + "` option.");
return null;
}
- opts[correspondences[args[i - 1]]] = args[i];
+ if (args[i - 1] !== "--test-file") {
+ opts[correspondences[args[i - 1]]] = args[i];
+ } else {
+ opts[correspondences[args[i - 1]]].push(args[i]);
+ }
} else if (args[i] === "--help") {
showHelp();
process.exit(0);
var errors = 0;
if (opts["test_file"].length !== 0) {
- errors += checkFile(opts["test_file"], opts, loaded, index);
- }
- if (opts["test_folder"].length !== 0) {
+ opts["test_file"].forEach(function(file) {
+ errors += checkFile(file, opts, loaded, index);
+ });
+ } else if (opts["test_folder"].length !== 0) {
fs.readdirSync(opts["test_folder"]).forEach(function(file) {
if (!file.endsWith(".js")) {
return;