gate_feature_post!(self, rustdoc_internals, attr.span, msg);
}
- if nested_meta.has_name(sym::tuple_variadic) {
- let msg = "`#[doc(tuple_variadic)]` is meant for internal use only";
+ if nested_meta.has_name(sym::fake_variadic) {
+ let msg = "`#[doc(fake_variadic)]` is meant for internal use only";
gate_feature_post!(self, rustdoc_internals, attr.span, msg);
}
}
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
#[derive(HashStable_Generic)]
pub enum StabilityLevel {
- // Reason for the current stability level and the relevant rust-lang issue
- Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
- Stable { since: Symbol, allowed_through_unstable_modules: bool },
+ /// `#[unstable]`
+ Unstable {
+ /// Reason for the current stability level.
+ reason: Option<Symbol>,
+ /// Relevant `rust-lang/rust` issue.
+ issue: Option<NonZeroU32>,
+ is_soft: bool,
+ /// If part of a feature is stabilized and a new feature is added for the remaining parts,
+ /// then the `implied_by` attribute is used to indicate which now-stable feature previously
+ /// contained a item.
+ ///
+ /// ```pseudo-Rust
+ /// #[unstable(feature = "foo", issue = "...")]
+ /// fn foo() {}
+ /// #[unstable(feature = "foo", issue = "...")]
+ /// fn foobar() {}
+ /// ```
+ ///
+ /// ...becomes...
+ ///
+ /// ```pseudo-Rust
+ /// #[stable(feature = "foo", since = "1.XX.X")]
+ /// fn foo() {}
+ /// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")]
+ /// fn foobar() {}
+ /// ```
+ implied_by: Option<Symbol>,
+ },
+ /// `#[stable]`
+ Stable {
+ /// Rust release which stabilized this feature.
+ since: Symbol,
+ /// Is this item allowed to be referred to on stable, despite being contained in unstable
+ /// modules?
+ allowed_through_unstable_modules: bool,
+ },
}
impl StabilityLevel {
let mut issue = None;
let mut issue_num = None;
let mut is_soft = false;
+ let mut implied_by = None;
for meta in metas {
let Some(mi) = meta.meta_item() else {
handle_errors(
}
is_soft = true;
}
+ sym::implied_by => {
+ if !get(mi, &mut implied_by) {
+ continue 'outer;
+ }
+ }
_ => {
handle_errors(
&sess.parse_sess,
);
continue;
}
- let level = Unstable { reason, issue: issue_num, is_soft };
+ let level = Unstable { reason, issue: issue_num, is_soft, implied_by };
if sym::unstable == meta_name {
stab = Some((Stability { level, feature }, attr.span));
} else {
meta.span(),
AttrError::UnknownMetaItem(
pprust::path_to_string(&mi.path),
- &["since", "note"],
+ &["feature", "since"],
),
);
continue 'outer;
use rustc_hir::def_id::LocalDefId;
use rustc_index::vec::IndexVec;
-use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
use rustc_middle::mir::Body;
use rustc_middle::ty::{self, TyCtxt};
def: ty::WithOptConstParam<LocalDefId>,
) -> BodyWithBorrowckFacts<'tcx> {
let (input_body, promoted) = tcx.mir_promoted(def);
- tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
+ tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).enter(|infcx| {
let input_body: &Body<'_> = &input_body.borrow();
let promoted: &IndexVec<_, _> = &promoted.borrow();
*super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
}
StorageDeadOrDrop::Destructor(_) => kind,
},
- ProjectionElem::OpaqueCast { .. }
- | ProjectionElem::Field(..)
- | ProjectionElem::Downcast(..) => {
+ ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
match place_ty.ty.kind() {
ty::Adt(def, _) if def.has_dtor(tcx) => {
// Report the outermost adt with a destructor
}
ProjectionElem::Downcast(..) if including_downcast.0 => return None,
ProjectionElem::Downcast(..) => (),
- ProjectionElem::OpaqueCast(..) => (),
ProjectionElem::Field(field, _ty) => {
// FIXME(project-rfc_2229#36): print capture precisely here.
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
}
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
- ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
},
};
..,
ProjectionElem::Index(_)
| ProjectionElem::ConstantIndex { .. }
- | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..),
],
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::ChunkedBitSet;
use rustc_index::vec::IndexVec;
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
use rustc_middle::mir::{
traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
PlaceRef, VarDebugInfoContents,
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
- let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| {
- let input_body: &Body<'_> = &input_body.borrow();
- let promoted: &IndexVec<_, _> = &promoted.borrow();
- do_mir_borrowck(&infcx, input_body, promoted, false).0
- });
+ let opt_closure_req = tcx
+ .infer_ctxt()
+ .with_opaque_type_inference(DefiningAnchor::Bind(hir_owner))
+ .enter(|infcx| {
+ let input_body: &Body<'_> = &input_body.borrow();
+ let promoted: &IndexVec<_, _> = &promoted.borrow();
+ do_mir_borrowck(&infcx, input_body, promoted, false).0
+ });
debug!("mir_borrowck done");
tcx.arena.alloc(opt_closure_req)
for (place_base, elem) in place.iter_projections().rev() {
match elem {
ProjectionElem::Index(_/*operand*/) |
- ProjectionElem::OpaqueCast(_) |
ProjectionElem::ConstantIndex { .. } |
// assigning to P[i] requires P to be valid.
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
- | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Downcast(..) => {
let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection {
| (ProjectionElem::Index { .. }, _, _)
| (ProjectionElem::ConstantIndex { .. }, _, _)
| (ProjectionElem::Subslice { .. }, _, _)
- | (ProjectionElem::OpaqueCast { .. }, _, _)
| (ProjectionElem::Downcast { .. }, _, _) => {
// Recursive case. This can still be disjoint on a
// further iteration if this a shallow access and
debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
Overlap::EqualOrDisjoint
}
- (ProjectionElem::OpaqueCast(v1), ProjectionElem::OpaqueCast(v2)) => {
- if v1 == v2 {
- // same type - recur.
- debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE");
- Overlap::EqualOrDisjoint
- } else {
- // Different types. Disjoint!
- debug!("place_element_conflict: DISJOINT-OPAQUE");
- Overlap::Disjoint
- }
- }
(ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => {
if f1 == f2 {
// same field (e.g., `a.y` vs. `a.y`) - recur.
| ProjectionElem::Field(..)
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
- | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..),
_,
}
ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
- | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Index(_) => {
cursor = cursor_base;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::OpaqueTyOrigin;
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
-use rustc_infer::infer::InferCtxt;
use rustc_infer::infer::TyCtxtInferExt as _;
+use rustc_infer::infer::{DefiningAnchor, InferCtxt};
use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
// FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
let param_env = self.tcx.param_env(def_id);
let body_id = self.tcx.local_def_id_to_hir_id(def_id);
- self.tcx.infer_ctxt().enter(move |infcx| {
- // Require the hidden type to be well-formed with only the generics of the opaque type.
- // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
- // hidden type is well formed even without those bounds.
- let predicate =
- ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
- .to_predicate(infcx.tcx);
- let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
-
- // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
- // the bounds that the function supplies.
- match infcx.register_hidden_type(
- OpaqueTypeKey { def_id, substs: id_substs },
- ObligationCause::misc(instantiated_ty.span, body_id),
- param_env,
- definition_ty,
- origin,
- ) {
- Ok(infer_ok) => {
- for obligation in infer_ok.obligations {
- fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+ // HACK This bubble is required for this tests to pass:
+ // type-alias-impl-trait/issue-67844-nested-opaque.rs
+ self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(
+ move |infcx| {
+ // Require the hidden type to be well-formed with only the generics of the opaque type.
+ // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
+ // hidden type is well formed even without those bounds.
+ let predicate =
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
+ .to_predicate(infcx.tcx);
+ let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+
+ // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
+ // the bounds that the function supplies.
+ match infcx.register_hidden_type(
+ OpaqueTypeKey { def_id, substs: id_substs },
+ ObligationCause::misc(instantiated_ty.span, body_id),
+ param_env,
+ definition_ty,
+ origin,
+ ) {
+ Ok(infer_ok) => {
+ for obligation in infer_ok.obligations {
+ fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+ }
+ }
+ Err(err) => {
+ infcx
+ .report_mismatched_types(
+ &ObligationCause::misc(instantiated_ty.span, body_id),
+ self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
+ definition_ty,
+ err,
+ )
+ .emit();
}
}
- Err(err) => {
- infcx
- .report_mismatched_types(
- &ObligationCause::misc(instantiated_ty.span, body_id),
- self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
- definition_ty,
- err,
- )
- .emit();
- }
- }
- fulfillment_cx.register_predicate_obligation(
- &infcx,
- Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
- );
+ fulfillment_cx.register_predicate_obligation(
+ &infcx,
+ Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
+ );
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = fulfillment_cx.select_all_or_error(&infcx);
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
- let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ // This is still required for many(half of the tests in ui/type-alias-impl-trait)
+ // tests to pass
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- if errors.is_empty() {
- definition_ty
- } else {
- infcx.report_fulfillment_errors(&errors, None, false);
- self.tcx.ty_error()
- }
- })
+ if errors.is_empty() {
+ definition_ty
+ } else {
+ infcx.report_fulfillment_errors(&errors, None, false);
+ self.tcx.ty_error()
+ }
+ },
+ )
} else {
definition_ty
}
use rustc_infer::infer::{
InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin,
};
+use rustc_infer::traits::ObligationCause;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::AssertKind;
)
.unwrap();
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
+ // Check that RPITs are only constrained in their outermost
+ // function, otherwise report a mismatched types error.
+ if let OpaqueTyOrigin::FnReturn(parent) | OpaqueTyOrigin::AsyncFn(parent)
+ = infcx.opaque_ty_origin_unchecked(opaque_type_key.def_id, hidden_type.span)
+ && parent.to_def_id() != body.source.def_id()
+ {
+ infcx
+ .report_mismatched_types(
+ &ObligationCause::misc(
+ hidden_type.span,
+ infcx.tcx.hir().local_def_id_to_hir_id(
+ body.source.def_id().expect_local(),
+ ),
+ ),
+ infcx.tcx.mk_opaque(opaque_type_key.def_id.to_def_id(), opaque_type_key.substs),
+ hidden_type.ty,
+ ty::error::TypeError::Mismatch,
+ )
+ .emit();
+ }
trace!(
"finalized opaque type {:?} to {:#?}",
opaque_type_key,
}
PlaceTy::from_ty(fty)
}
- ProjectionElem::OpaqueCast(ty) => {
- let ty = self.sanitize_type(place, ty);
- let ty = self.cx.normalize(ty, location);
- self.cx
- .eq_types(
- base.ty,
- ty,
- location.to_locations(),
- ConstraintCategory::TypeAnnotation,
- )
- .unwrap();
- PlaceTy::from_ty(ty)
- }
}
}
tcx,
self.param_env,
proj,
- |this, field, _| {
+ |this, field, ()| {
let ty = this.field_ty(tcx, field);
self.normalize(ty, locations)
},
- |_, _| unreachable!(),
);
curr_projected_ty = projected_ty;
}
}
ProjectionElem::Field(..)
| ProjectionElem::Downcast(..)
- | ProjectionElem::OpaqueCast(..)
| ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
let opt_trait_ref = Some(trait_ref);
- let unused_qual = {
- let word = rustc_ast::attr::mk_nested_word_item(Ident::new(
- sym::unused_qualifications,
- self.span,
- ));
- let list = rustc_ast::attr::mk_list_item(Ident::new(sym::allow, self.span), vec![word]);
- cx.attribute(list)
- };
- let mut a = vec![attr, unused_qual];
+ let mut a = vec![attr];
a.extend(self.attributes.iter().cloned());
cx.item(
cplace = cplace.place_deref(fx);
}
}
- PlaceElem::OpaqueCast(ty) => cplace = cplace.place_opaque_cast(fx, ty),
PlaceElem::Field(field, _ty) => {
cplace = cplace.place_field(fx, field);
}
}
}
- pub(crate) fn place_opaque_cast(
- self,
- fx: &mut FunctionCx<'_, '_, 'tcx>,
- ty: Ty<'tcx>,
- ) -> CPlace<'tcx> {
- CPlace { inner: self.inner, layout: fx.layout_of(ty) }
- }
-
pub(crate) fn place_field(
self,
fx: &mut FunctionCx<'_, '_, 'tcx>,
downcast
}
- pub fn project_type<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
- &self,
- bx: &mut Bx,
- ty: Ty<'tcx>,
- ) -> Self {
- let mut downcast = *self;
- downcast.layout = bx.cx().layout_of(ty);
-
- // Cast to the appropriate type.
- let variant_ty = bx.cx().backend_type(downcast.layout);
- downcast.llval = bx.pointercast(downcast.llval, bx.cx().type_ptr_to(variant_ty));
-
- downcast
- }
-
pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
bx.lifetime_start(self.llval, self.layout.size);
}
mir::ProjectionElem::Field(ref field, _) => {
cg_base.project_field(bx, field.index())
}
- mir::ProjectionElem::OpaqueCast(ty) => cg_base.project_type(bx, ty),
mir::ProjectionElem::Index(index) => {
let index = &mir::Operand::Copy(mir::Place::from(index));
let index = self.codegen_operand(bx, index);
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
use rustc_middle::mir::ProjectionElem::*;
Ok(match proj_elem {
- OpaqueCast(ty) => {
- let mut place = base.clone();
- place.layout = self.layout_of(ty)?;
- place
- }
Field(field, _) => self.place_field(base, field.index())?,
Downcast(_, variant) => self.place_downcast(base, variant)?,
Deref => self.deref_operand(&self.place_to_op(base)?)?.into(),
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc_middle::mir::ProjectionElem::*;
Ok(match proj_elem {
- OpaqueCast(ty) => {
- let mut op = base.clone();
- op.layout = self.layout_of(ty)?;
- op
- }
Field(field, _) => self.operand_field(base, field.index())?,
Downcast(_, variant) => self.operand_downcast(base, variant)?,
Deref => self.deref_operand(base)?.into(),
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Downcast(..)
- | ProjectionElem::OpaqueCast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::Field(..)
| ProjectionElem::Index(_) => {}
ProjectionElem::Deref
| ProjectionElem::Field(_, _)
- | ProjectionElem::OpaqueCast(_)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(_, _)
return Err(Unpromotable);
}
}
- ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => {
+ ProjectionElem::Downcast(..) => {
return Err(Unpromotable);
}
Erroneous code example:
```compile_fail,E0118
-impl fn(u8) { // error: no nominal type found for inherent implementation
+impl<T> T { // error: no nominal type found for inherent implementation
fn get_state(&self) -> String {
// ...
}
fn get_state(&self) -> String;
}
-// and now you can implement it on fn(u8)
-impl LiveLongAndProsper for fn(u8) {
+// and now you can implement it on T
+impl<T> LiveLongAndProsper for T {
fn get_state(&self) -> String {
"He's dead, Jim!".to_owned()
}
Example:
```
-struct TypeWrapper(fn(u8));
+struct TypeWrapper<T>(T);
-impl TypeWrapper {
+impl<T> TypeWrapper<T> {
fn get_state(&self) -> String {
"Fascinating!".to_owned()
}
passes-doc-keyword-invalid-ident = `{$doc_keyword}` is not a valid identifier
-passes-doc-tuple-variadic-not-first =
- `#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity
+passes-doc-fake-variadic-not-valid =
+ `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity
passes-doc-keyword-only-impl = `#[doc(keyword = "...")]` should be used on impl blocks
span: Span,
ty: &str,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
- cx.struct_span_err(span, &format!("{ty} depth must be less than {max}"))
+ let msg = if max == 0 {
+ format!(
+ "meta-variable expression `{ty}` with depth parameter \
+ must be called inside of a macro repetition"
+ )
+ } else {
+ format!(
+ "depth parameter on meta-variable expression `{ty}` \
+ must be less than {max}"
+ )
+ };
+ cx.struct_span_err(span, &msg)
}
fn transcribe_metavar_expr<'a>(
}
}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum DefiningAnchor {
+ /// `DefId` of the item.
+ Bind(LocalDefId),
+ /// When opaque types are not resolved, we `Bubble` up, meaning
+ /// return the opaque/hidden type pair from query, for caller of query to handle it.
+ Bubble,
+ /// Used to catch type mismatch errors when handling opaque types.
+ Error,
+}
+
pub struct InferCtxt<'a, 'tcx> {
pub tcx: TyCtxt<'tcx>,
/// The `DefId` of the item in whose context we are performing inference or typeck.
/// It is used to check whether an opaque type use is a defining use.
///
- /// If it is `None`, we can't resolve opaque types here and need to bubble up
+ /// If it is `DefiningAnchor::Bubble`, we can't resolve opaque types here and need to bubble up
/// the obligation. This frequently happens for
/// short lived InferCtxt within queries. The opaque type obligations are forwarded
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
- pub defining_use_anchor: Option<LocalDefId>,
+ ///
+ /// It is default value is `DefiningAnchor::Error`, this way it is easier to catch errors that
+ /// might come up during inference or typeck.
+ pub defining_use_anchor: DefiningAnchor,
/// During type-checking/inference of a body, `in_progress_typeck_results`
/// contains a reference to the typeck results being built up, which are
pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
- defining_use_anchor: Option<LocalDefId>,
+ defining_use_anchor: DefiningAnchor,
}
pub trait TyCtxtInferExt<'tcx> {
impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
- InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
+ InferCtxtBuilder {
+ tcx: self,
+ defining_use_anchor: DefiningAnchor::Error,
+ fresh_typeck_results: None,
+ }
}
}
/// Will also change the scope for opaque type defining use checks to the given owner.
pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
- self.with_opaque_type_inference(table_owner)
+ self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner))
}
/// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
/// It is only meant to be called in two places, for typeck
/// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
/// in mir borrowck.
- pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self {
- self.defining_use_anchor = Some(defining_use_anchor);
+ pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor) -> Self {
+ self.defining_use_anchor = defining_use_anchor;
self
}
-use crate::infer::{InferCtxt, InferOk};
+use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
use crate::traits;
use hir::def_id::{DefId, LocalDefId};
use hir::{HirId, OpaqueTyOrigin};
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
ty::Opaque(def_id, substs) if def_id.is_local() => {
let def_id = def_id.expect_local();
- let origin = if self.defining_use_anchor.is_some() {
- // Check that this is `impl Trait` type is
- // declared by `parent_def_id` -- i.e., one whose
- // value we are inferring. At present, this is
- // always true during the first phase of
- // type-check, but not always true later on during
- // NLL. Once we support named opaque types more fully,
- // this same scenario will be able to arise during all phases.
- //
- // Here is an example using type alias `impl Trait`
- // that indicates the distinction we are checking for:
- //
- // ```rust
- // mod a {
- // pub type Foo = impl Iterator;
- // pub fn make_foo() -> Foo { .. }
- // }
- //
- // mod b {
- // fn foo() -> a::Foo { a::make_foo() }
- // }
- // ```
- //
- // Here, the return type of `foo` references an
- // `Opaque` indeed, but not one whose value is
- // presently being inferred. You can get into a
- // similar situation with closure return types
- // today:
- //
- // ```rust
- // fn foo() -> impl Iterator { .. }
- // fn bar() {
- // let x = || foo(); // returns the Opaque assoc with `foo`
- // }
- // ```
- self.opaque_type_origin(def_id, cause.span)?
- } else {
- self.opaque_ty_origin_unchecked(def_id, cause.span)
+ let origin = match self.defining_use_anchor {
+ DefiningAnchor::Bind(_) => {
+ // Check that this is `impl Trait` type is
+ // declared by `parent_def_id` -- i.e., one whose
+ // value we are inferring. At present, this is
+ // always true during the first phase of
+ // type-check, but not always true later on during
+ // NLL. Once we support named opaque types more fully,
+ // this same scenario will be able to arise during all phases.
+ //
+ // Here is an example using type alias `impl Trait`
+ // that indicates the distinction we are checking for:
+ //
+ // ```rust
+ // mod a {
+ // pub type Foo = impl Iterator;
+ // pub fn make_foo() -> Foo { .. }
+ // }
+ //
+ // mod b {
+ // fn foo() -> a::Foo { a::make_foo() }
+ // }
+ // ```
+ //
+ // Here, the return type of `foo` references an
+ // `Opaque` indeed, but not one whose value is
+ // presently being inferred. You can get into a
+ // similar situation with closure return types
+ // today:
+ //
+ // ```rust
+ // fn foo() -> impl Iterator { .. }
+ // fn bar() {
+ // let x = || foo(); // returns the Opaque assoc with `foo`
+ // }
+ // ```
+ self.opaque_type_origin(def_id, cause.span)?
+ }
+ DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span),
+ DefiningAnchor::Error => return None,
};
if let ty::Opaque(did2, _) = *b.kind() {
// We could accept this, but there are various ways to handle this situation, and we don't
#[instrument(skip(self), level = "trace")]
pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<OpaqueTyOrigin> {
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let parent_def_id = self.defining_use_anchor?;
+ let parent_def_id = match self.defining_use_anchor {
+ DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
+ DefiningAnchor::Bind(bind) => bind,
+ };
let item_kind = &self.tcx.hir().expect_item(def_id).kind;
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
}
#[instrument(skip(self), level = "trace")]
- fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin {
+ pub fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin {
let origin = match self.tcx.hir().expect_item(def_id).kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
ref itemkind => {
tracked!(asm_comments, true);
tracked!(assume_incomplete_release, true);
tracked!(binary_dep_depinfo, true);
+ tracked!(box_noalias, Some(false));
tracked!(
branch_protection,
Some(BranchProtection {
let a_poly_sig = a.fn_sig(tcx);
let b_poly_sig = b.fn_sig(tcx);
- // As we don't compare regions, skip_binder is fine.
- let a_sig = a_poly_sig.skip_binder();
- let b_sig = b_poly_sig.skip_binder();
+ // We don't compare regions, but leaving bound regions around ICEs, so
+ // we erase them.
+ let a_sig = tcx.erase_late_bound_regions(a_poly_sig);
+ let b_sig = tcx.erase_late_bound_regions(b_poly_sig);
(a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
== (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
+const OPTIONAL_COMPONENTS: &[&str] = &[
+ "x86",
+ "arm",
+ "aarch64",
+ "amdgpu",
+ "avr",
+ "m68k",
+ "mips",
+ "powerpc",
+ "systemz",
+ "jsbackend",
+ "webassembly",
+ "msp430",
+ "sparc",
+ "nvptx",
+ "hexagon",
+ "riscv",
+ "bpf",
+];
+
+const REQUIRED_COMPONENTS: &[&str] =
+ &["ipo", "bitreader", "bitwriter", "linker", "asmparser", "lto", "coverage", "instrumentation"];
+
fn detect_llvm_link() -> (&'static str, &'static str) {
// Force the link mode we want, preferring static by default, but
// possibly overridden by `configure --enable-llvm-link-shared`.
}
fn main() {
+ for component in REQUIRED_COMPONENTS.iter().chain(OPTIONAL_COMPONENTS.iter()) {
+ println!("cargo:rustc-check-cfg=values(llvm_component,\"{}\")", component);
+ }
+
if tracked_env_var_os("RUST_CHECK").is_some() {
// If we're just running `check`, there's no need for LLVM to be built.
return;
let host = env::var("HOST").expect("HOST was not set");
let is_crossed = target != host;
- let optional_components = &[
- "x86",
- "arm",
- "aarch64",
- "amdgpu",
- "avr",
- "m68k",
- "mips",
- "powerpc",
- "systemz",
- "jsbackend",
- "webassembly",
- "msp430",
- "sparc",
- "nvptx",
- "hexagon",
- "riscv",
- "bpf",
- ];
-
- let required_components = &[
- "ipo",
- "bitreader",
- "bitwriter",
- "linker",
- "asmparser",
- "lto",
- "coverage",
- "instrumentation",
- ];
-
let components = output(Command::new(&llvm_config).arg("--components"));
let mut components = components.split_whitespace().collect::<Vec<_>>();
- components.retain(|c| optional_components.contains(c) || required_components.contains(c));
+ components.retain(|c| OPTIONAL_COMPONENTS.contains(c) || REQUIRED_COMPONENTS.contains(c));
- for component in required_components {
+ for component in REQUIRED_COMPONENTS {
if !components.contains(component) {
panic!("require llvm component {} but wasn't found", component);
}
tcx.arena.alloc_from_iter(self.root.lib_features.decode(self))
}
+ /// Iterates over the stability implications in the given crate (when a `#[unstable]` attribute
+ /// has an `implied_by` meta item, then the mapping from the implied feature to the actual
+ /// feature is a stability implication).
+ fn get_stability_implications(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Symbol)] {
+ tcx.arena.alloc_from_iter(self.root.stability_implications.decode(self))
+ }
+
/// Iterates over the language items in the given crate.
fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
tcx.arena.alloc_from_iter(
tcx.arena.alloc_slice(&result)
}
defined_lib_features => { cdata.get_lib_features(tcx) }
+ stability_implications => {
+ cdata.get_stability_implications(tcx).iter().copied().collect()
+ }
is_intrinsic => { cdata.get_is_intrinsic(def_id.index) }
defined_lang_items => { cdata.get_lang_items(tcx) }
diagnostic_items => { cdata.get_diagnostic_items() }
let lib_features = self.encode_lib_features();
let lib_feature_bytes = self.position() - i;
+ // Encode the stability implications.
+ i = self.position();
+ let stability_implications = self.encode_stability_implications();
+ let stability_implications_bytes = self.position() - i;
+
// Encode the language items.
i = self.position();
let lang_items = self.encode_lang_items();
crate_deps,
dylib_dependency_formats,
lib_features,
+ stability_implications,
lang_items,
diagnostic_items,
lang_items_missing,
let computed_total_bytes = preamble_bytes
+ dep_bytes
+ lib_feature_bytes
+ + stability_implications_bytes
+ lang_item_bytes
+ diagnostic_item_bytes
+ native_lib_bytes
p("preamble", preamble_bytes);
p("dep", dep_bytes);
p("lib feature", lib_feature_bytes);
+ p("stability_implications", stability_implications_bytes);
p("lang item", lang_item_bytes);
p("diagnostic item", diagnostic_item_bytes);
p("native lib", native_lib_bytes);
self.lazy_array(lib_features.to_vec())
}
+ fn encode_stability_implications(&mut self) -> LazyArray<(Symbol, Symbol)> {
+ empty_proc_macro!(self);
+ let tcx = self.tcx;
+ let implications = tcx.stability_implications(LOCAL_CRATE);
+ self.lazy_array(implications.iter().map(|(k, v)| (*k, *v)))
+ }
+
fn encode_diagnostic_items(&mut self) -> LazyArray<(Symbol, DefIndex)> {
empty_proc_macro!(self);
let tcx = self.tcx;
crate_deps: LazyArray<CrateDep>,
dylib_dependency_formats: LazyArray<Option<LinkagePreference>>,
lib_features: LazyArray<(Symbol, Option<Symbol>)>,
+ stability_implications: LazyArray<(Symbol, Symbol)>,
lang_items: LazyArray<(DefIndex, usize)>,
lang_items_missing: LazyArray<lang_items::LangItem>,
diagnostic_items: LazyArray<(Symbol, DefIndex)>,
pub mod exported_symbols;
pub mod lang_items;
pub mod lib_features {
- use rustc_data_structures::fx::{FxHashMap, FxHashSet};
- use rustc_span::symbol::Symbol;
+ use rustc_data_structures::fx::FxHashMap;
+ use rustc_span::{symbol::Symbol, Span};
#[derive(HashStable, Debug)]
pub struct LibFeatures {
- // A map from feature to stabilisation version.
- pub stable: FxHashMap<Symbol, Symbol>,
- pub unstable: FxHashSet<Symbol>,
+ /// A map from feature to stabilisation version.
+ pub stable: FxHashMap<Symbol, (Symbol, Span)>,
+ pub unstable: FxHashMap<Symbol, Span>,
}
impl LibFeatures {
let mut all_features: Vec<_> = self
.stable
.iter()
- .map(|(f, s)| (*f, Some(*s)))
- .chain(self.unstable.iter().map(|f| (*f, None)))
+ .map(|(f, (s, _))| (*f, Some(*s)))
+ .chain(self.unstable.iter().map(|(f, _)| (*f, None)))
.collect();
all_features.sort_unstable_by(|a, b| a.0.as_str().partial_cmp(b.0.as_str()).unwrap());
all_features
pub stab_map: FxHashMap<LocalDefId, Stability>,
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
+ /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
+ /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
+ /// exists, then this map will have a `impliee -> implier` entry.
+ ///
+ /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should
+ /// specify their implications (both `implies` and `implied_by`). If only one of the two
+ /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this
+ /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is
+ /// reported, only the `#[stable]` attribute information is available, so the map is necessary
+ /// to know that the feature implies another feature. If it were reversed, and the `#[stable]`
+ /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of
+ /// unstable feature" error for a feature that was implied.
+ pub implications: FxHashMap<Symbol, Symbol>,
}
impl Index {
match stability {
Some(Stability {
- level: attr::Unstable { reason, issue, is_soft }, feature, ..
+ level: attr::Unstable { reason, issue, is_soft, implied_by },
+ feature,
+ ..
}) => {
if span.allows_unstable(feature) {
debug!("stability: skipping span={:?} since it is internal", span);
return EvalResult::Allow;
}
+ // If this item was previously part of a now-stabilized feature which is still
+ // active (i.e. the user hasn't removed the attribute for the stabilized feature
+ // yet) then allow use of this item.
+ if let Some(implied_by) = implied_by && self.features().active(implied_by) {
+ return EvalResult::Allow;
+ }
+
// When we're compiling the compiler itself we may pull in
// crates from crates.io, but those crates may depend on other
// crates also pulled in from crates.io. We want to ideally be
Self::Field(_, _)
| Self::Index(_)
- | Self::OpaqueCast(_)
| Self::ConstantIndex { .. }
| Self::Subslice { .. }
| Self::Downcast(_, _) => false,
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
for elem in self.projection.iter().rev() {
match elem {
- ProjectionElem::OpaqueCast(_)
- | ProjectionElem::Downcast(_, _)
- | ProjectionElem::Field(_, _) => {
+ ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
write!(fmt, "(").unwrap();
}
ProjectionElem::Deref => {
for elem in self.projection.iter() {
match elem {
- ProjectionElem::OpaqueCast(ty) => {
- write!(fmt, " as {})", ty)?;
- }
ProjectionElem::Downcast(Some(name), _index) => {
write!(fmt, " as {})", name)?;
}
/// generator has more than one variant, the parent place's variant index must be set, indicating
/// which variant is being used. If it has just one variant, the variant index may or may not be
/// included - the single possible variant is inferred if it is not included.
-/// - [`OpaqueCast`](ProjectionElem::OpaqueCast): This projection changes the place's type to the
-/// given one, and makes no other changes. A `OpaqueCast` projection on any type other than an
-/// opaque type from the current crate is not well-formed.
/// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the
/// place as described in the documentation for the `ProjectionElem`. The resulting address is
/// the parent's address plus that offset, and the type is `T`. This is only legal if the parent
///
/// The included Symbol is the name of the variant, used for printing MIR.
Downcast(Option<Symbol>, VariantIdx),
-
- /// Like an explicit cast from an opaque type to a concrete type, but without
- /// requiring an intermediate variable.
- OpaqueCast(T),
}
/// Alias for projections as they appear in places, where the base is a place
/// `PlaceElem`, where we can just use the `Ty` that is already
/// stored inline on field projection elems.
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
- self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty)
+ self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty)
}
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
param_env: ty::ParamEnv<'tcx>,
elem: &ProjectionElem<V, T>,
mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>,
- mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>,
) -> PlaceTy<'tcx>
where
V: ::std::fmt::Debug,
PlaceTy { ty: self.ty, variant_index: Some(index) }
}
ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
- ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)),
};
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
answer
Ok(match self {
Deref => Deref,
Field(f, ty) => Field(f, ty.try_fold_with(folder)?),
- OpaqueCast(ty) => OpaqueCast(ty.try_fold_with(folder)?),
Index(v) => Index(v.try_fold_with(folder)?),
Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
ConstantIndex { offset, min_length, from_end } => {
self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
}
- PlaceElem::OpaqueCast(ty) => {
- let mut new_ty = ty;
- self.visit_ty(&mut new_ty, TyContext::Location(location));
- if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
- }
PlaceElem::Deref
| PlaceElem::ConstantIndex { .. }
| PlaceElem::Subslice { .. }
location: Location,
) {
match elem {
- ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => {
+ ProjectionElem::Field(_field, ty) => {
self.visit_ty(ty, TyContext::Location(location));
}
ProjectionElem::Index(local) => {
storage(ArenaCacheSelector<'tcx>)
desc { "calculating the lib features map" }
}
- query defined_lib_features(_: CrateNum)
- -> &'tcx [(Symbol, Option<Symbol>)] {
+ query defined_lib_features(_: CrateNum) -> &'tcx [(Symbol, Option<Symbol>)] {
desc { "calculating the lib features defined in a crate" }
separate_provide_extern
}
+ query stability_implications(_: CrateNum) -> FxHashMap<Symbol, Symbol> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "calculating the implications between `#[unstable]` features defined in a crate" }
+ separate_provide_extern
+ }
/// Whether the function is an intrinsic
query is_intrinsic(def_id: DefId) -> bool {
desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) }
// this attribute doesn't make it UB for the pointed-to data to be undef.
attrs.set(ArgAttribute::NoUndef);
- // `Box` pointer parameters never alias because ownership is transferred
+ // The aliasing rules for `Box<T>` are still not decided, but currently we emit
+ // `noalias` for it. This can be turned off using an unstable flag.
+ // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326
+ let noalias_for_box =
+ self.tcx().sess.opts.unstable_opts.box_noalias.unwrap_or(true);
+
// `&mut` pointer parameters never alias other parameters,
// or mutable global data
//
// `-Zmutable-noalias` debugging option.
let no_alias = match kind {
PointerKind::Shared | PointerKind::UniqueBorrowed => false,
- PointerKind::UniqueOwned => true,
+ PointerKind::UniqueOwned => noalias_for_box,
PointerKind::Frozen => !is_return,
};
if no_alias {
use rustc_middle::hir::place::Projection as HirProjection;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
use rustc_middle::middle::region;
-use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::AssertKind::BoundsCheck;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
/// This is used internally when building a place for an expression like `a.b.c`. The fields `b`
/// and `c` can be progressively pushed onto the place builder that is created when converting `a`.
#[derive(Clone, Debug, PartialEq)]
-pub(in crate::build) struct PlaceBuilder<'tcx> {
+pub(crate) struct PlaceBuilder<'tcx> {
base: PlaceBase,
projection: Vec<PlaceElem<'tcx>>,
}
variant = Some(*idx);
continue;
}
- // These do not affect anything, they just make sure we know the right type.
- ProjectionElem::OpaqueCast(_) => continue,
ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
/// `PlaceBuilder` now starts from `PlaceBase::Local`.
///
/// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found.
-#[instrument(level = "trace", skip(cx))]
-fn to_upvars_resolved_place_builder<'tcx>(
+fn to_upvars_resolved_place_builder<'a, 'tcx>(
from_builder: PlaceBuilder<'tcx>,
- cx: &Builder<'_, 'tcx>,
+ tcx: TyCtxt<'tcx>,
+ typeck_results: &'a ty::TypeckResults<'tcx>,
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
match from_builder.base {
PlaceBase::Local(_) => Ok(from_builder),
let Some((capture_index, capture)) =
find_capture_matching_projections(
- cx.typeck_results,
+ typeck_results,
var_hir_id,
closure_def_id,
&from_builder.projection,
) else {
- let closure_span = cx.tcx.def_span(closure_def_id);
- if !enable_precise_capture(cx.tcx, closure_span) {
+ let closure_span = tcx.def_span(closure_def_id);
+ if !enable_precise_capture(tcx, closure_span) {
bug!(
"No associated capture found for {:?}[{:#?}] even though \
capture_disjoint_fields isn't enabled",
};
// We won't be building MIR if the closure wasn't local
- let closure_hir_id = cx.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
- let closure_ty = cx.typeck_results.node_type(closure_hir_id);
+ let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
+ let closure_ty = typeck_results.node_type(closure_hir_id);
let substs = match closure_ty.kind() {
ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
// We used some of the projections to build the capture itself,
// now we apply the remaining to the upvar resolved place.
- trace!(?capture.place, ?from_builder.projection);
let remaining_projections = strip_prefix(
capture.place.base_ty,
from_builder.projection,
&capture.place.projections,
);
upvar_resolved_place_builder.projection.extend(remaining_projections);
- trace!(?upvar_resolved_place_builder);
Ok(upvar_resolved_place_builder)
}
prefix_projections: &[HirProjection<'tcx>],
) -> impl Iterator<Item = PlaceElem<'tcx>> {
let mut iter = projections.into_iter();
- let mut next = || match iter.next()? {
- // Filter out opaque casts, they are unnecessary in the prefix.
- ProjectionElem::OpaqueCast(..) => iter.next(),
- other => Some(other),
- };
for projection in prefix_projections {
match projection.kind {
HirProjectionKind::Deref => {
- assert!(matches!(next(), Some(ProjectionElem::Deref)));
+ assert!(matches!(iter.next(), Some(ProjectionElem::Deref)));
}
HirProjectionKind::Field(..) => {
if base_ty.is_enum() {
- assert!(matches!(next(), Some(ProjectionElem::Downcast(..))));
+ assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..))));
}
- assert!(matches!(next(), Some(ProjectionElem::Field(..))));
+ assert!(matches!(iter.next(), Some(ProjectionElem::Field(..))));
}
HirProjectionKind::Index | HirProjectionKind::Subslice => {
bug!("unexpected projection kind: {:?}", projection);
}
impl<'tcx> PlaceBuilder<'tcx> {
- pub(crate) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> {
+ pub(crate) fn into_place<'a>(
+ self,
+ tcx: TyCtxt<'tcx>,
+ typeck_results: &'a ty::TypeckResults<'tcx>,
+ ) -> Place<'tcx> {
if let PlaceBase::Local(local) = self.base {
- let mut projections = vec![];
- let mut ty = PlaceTy::from_ty(cx.local_decls[local].ty);
- for projection in self.projection {
- // Only preserve those opaque casts that actually go from an opaque type
- // to another type.
- if let ProjectionElem::OpaqueCast(t) = projection {
- if let ty::Opaque(..) = ty.ty.kind() {
- if t != ty.ty {
- projections.push(ProjectionElem::OpaqueCast(t));
- }
- }
- } else {
- projections.push(projection);
- }
- ty = ty.projection_ty(cx.tcx, projection);
- }
- Place { local, projection: cx.tcx.intern_place_elems(&projections) }
+ Place { local, projection: tcx.intern_place_elems(&self.projection) }
} else {
- self.expect_upvars_resolved(cx).into_place(cx)
+ self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
}
}
- fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> {
- to_upvars_resolved_place_builder(self, cx).unwrap()
+ fn expect_upvars_resolved<'a>(
+ self,
+ tcx: TyCtxt<'tcx>,
+ typeck_results: &'a ty::TypeckResults<'tcx>,
+ ) -> PlaceBuilder<'tcx> {
+ to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
}
/// Attempts to resolve the `PlaceBuilder`.
/// not captured. This can happen because the final mir that will be
/// generated doesn't require a read for this place. Failures will only
/// happen inside closures.
- pub(crate) fn try_upvars_resolved(
+ pub(crate) fn try_upvars_resolved<'a>(
self,
- cx: &Builder<'_, 'tcx>,
+ tcx: TyCtxt<'tcx>,
+ typeck_results: &'a ty::TypeckResults<'tcx>,
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
- to_upvars_resolved_place_builder(self, cx)
+ to_upvars_resolved_place_builder(self, tcx, typeck_results)
}
pub(crate) fn base(&self) -> PlaceBase {
expr: &Expr<'tcx>,
) -> BlockAnd<Place<'tcx>> {
let place_builder = unpack!(block = self.as_place_builder(block, expr));
- block.and(place_builder.into_place(self))
+ block.and(place_builder.into_place(self.tcx, self.typeck_results))
}
/// This is used when constructing a compound `Place`, so that we can avoid creating
expr: &Expr<'tcx>,
) -> BlockAnd<Place<'tcx>> {
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
- block.and(place_builder.into_place(self))
+ block.and(place_builder.into_place(self.tcx, self.typeck_results))
}
/// This is used when constructing a compound `Place`, so that we can avoid creating
inferred_ty: expr.ty,
});
- let place = place_builder.clone().into_place(this);
+ let place = place_builder.clone().into_place(this.tcx, this.typeck_results);
this.cfg.push(
block,
Statement {
if is_outermost_index {
self.read_fake_borrows(block, fake_borrow_temps, source_info)
} else {
- base_place = base_place.expect_upvars_resolved(self);
+ base_place = base_place.expect_upvars_resolved(self.tcx, self.typeck_results);
self.add_fake_borrows_of_base(
&base_place,
block,
let lt = self.temp(bool_ty, expr_span);
// len = len(slice)
- self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.into_place(self)));
+ self.cfg.push_assign(
+ block,
+ source_info,
+ len,
+ Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)),
+ );
// lt = idx < len
self.cfg.push_assign(
block,
}
ProjectionElem::Field(..)
| ProjectionElem::Downcast(..)
- | ProjectionElem::OpaqueCast(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => (),
}
let place_builder =
unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
- if let Ok(place_builder_resolved) = place_builder.try_upvars_resolved(this) {
- let mir_place = place_builder_resolved.into_place(this);
+ if let Ok(place_builder_resolved) =
+ place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
+ {
+ let mir_place =
+ place_builder_resolved.into_place(this.tcx, this.typeck_results);
this.cfg.push_fake_read(
block,
this.source_info(this.tcx.hir().span(*hir_id)),
// by the parent itself. The mutability of the current capture
// is same as that of the capture in the parent closure.
PlaceBase::Upvar { .. } => {
- let enclosing_upvars_resolved = arg_place_builder.clone().into_place(this);
+ let enclosing_upvars_resolved =
+ arg_place_builder.clone().into_place(this.tcx, this.typeck_results);
match enclosing_upvars_resolved.as_ref() {
PlaceRef {
Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
};
- let arg_place = arg_place_builder.into_place(this);
+ let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results);
this.cfg.push_assign(
block,
ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability))
}
- #[instrument(skip(self), level = "debug")]
fn as_temp_inner(
&mut self,
mut block: BasicBlock,
expr: &Expr<'tcx>,
mutability: Mutability,
) -> BlockAnd<Local> {
+ debug!(
+ "as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
+ block, temp_lifetime, expr, mutability
+ );
let this = self;
let expr_span = expr.span;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, storing the result into `destination`, which
/// is assumed to be uninitialized.
- #[instrument(level = "debug", skip(self))]
pub(crate) fn expr_into_dest(
&mut self,
destination: Place<'tcx>,
mut block: BasicBlock,
expr: &Expr<'tcx>,
) -> BlockAnd<()> {
+ debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
+
// since we frequently have to reference `self` from within a
// closure, where `self` would be shadowed, it's easier to
// just use the name `this` uniformly
None => {
let place_builder = place_builder.clone();
this.consume_by_copy_or_move(
- place_builder.field(n, *ty).into_place(this),
+ place_builder
+ .field(n, *ty)
+ .into_place(this.tcx, this.typeck_results),
)
}
})
let cause_matched_place = FakeReadCause::ForMatchedPlace(None);
let source_info = self.source_info(scrutinee_span);
- if let Ok(scrutinee_builder) = scrutinee_place_builder.clone().try_upvars_resolved(self) {
- let scrutinee_place = scrutinee_builder.into_place(self);
+ if let Ok(scrutinee_builder) =
+ scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+ {
+ let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results);
self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
}
// ```
let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
let scrutinee_place: Place<'tcx>;
- if let Ok(scrutinee_builder) =
- scrutinee_place_builder.clone().try_upvars_resolved(this)
+ if let Ok(scrutinee_builder) = scrutinee_place_builder
+ .clone()
+ .try_upvars_resolved(this.tcx, this.typeck_results)
{
- scrutinee_place = scrutinee_builder.into_place(this);
+ scrutinee_place =
+ scrutinee_builder.into_place(this.tcx, this.typeck_results);
opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
}
let scope = this.declare_bindings(
while let Some(next) = {
for binding in &candidate_ref.bindings {
let local = self.var_local_id(binding.var_id, OutsideGuard);
+
+ let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
+ )))) = self.local_decls[local].local_info else {
+ bug!("Let binding to non-user variable.")
+ };
// `try_upvars_resolved` may fail if it is unable to resolve the given
// `PlaceBuilder` inside a closure. In this case, we don't want to include
// a scrutinee place. `scrutinee_place_builder` will fail for destructured
// let (v1, v2) = foo;
// };
// ```
- if let Ok(match_pair_resolved) = initializer.clone().try_upvars_resolved(self) {
- let place = match_pair_resolved.into_place(self);
-
- let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
- VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
- )))) = self.local_decls[local].local_info else {
- bug!("Let binding to non-user variable.")
- };
-
+ if let Ok(match_pair_resolved) =
+ initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+ {
+ let place = match_pair_resolved.into_place(self.tcx, self.typeck_results);
*match_place = Some(place);
}
}
/// scope for the bindings in these patterns, if such a scope had to be
/// created. NOTE: Declaring the bindings should always be done in their
/// drop scope.
- #[instrument(skip(self), level = "debug")]
pub(crate) fn declare_bindings(
&mut self,
mut visibility_scope: Option<SourceScope>,
has_guard: ArmHasGuard,
opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,
) -> Option<SourceScope> {
+ debug!("declare_bindings: pattern={:?}", pattern);
self.visit_primary_bindings(
&pattern,
UserTypeProjections::none(),
Candidate {
span: pattern.span,
has_guard,
- match_pairs: smallvec![MatchPair::new(place, pattern)],
+ match_pairs: smallvec![MatchPair { place, pattern }],
bindings: Vec::new(),
ascriptions: Vec::new(),
subcandidates: Vec::new(),
/// if `x.0` matches `false` (for the third arm). In the (impossible at
/// runtime) case when `x.0` is now `true`, we branch to
/// `otherwise_block`.
- #[instrument(skip(self, fake_borrows), level = "debug")]
fn match_candidates<'pat>(
&mut self,
span: Span,
candidates: &mut [&mut Candidate<'pat, 'tcx>],
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
+ debug!(
+ "matched_candidate(span={:?}, candidates={:?}, start_block={:?}, otherwise_block={:?})",
+ span, candidates, start_block, otherwise_block,
+ );
+
// Start by simplifying candidates. Once this process is complete, all
// the match pairs which remain require some form of test, whether it
// be a switch or pattern comparison.
)
}
- #[instrument(
- skip(self, otherwise, or_span, place, fake_borrows, candidate, pats),
- level = "debug"
- )]
fn test_or_pattern<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
place: PlaceBuilder<'tcx>,
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
- debug!("candidate={:#?}\npats={:#?}", candidate, pats);
+ debug!("test_or_pattern:\ncandidate={:#?}\npats={:#?}", candidate, pats);
let mut or_candidates: Vec<_> = pats
.iter()
.map(|pat| Candidate::new(place.clone(), pat, candidate.has_guard))
// Insert a Shallow borrow of any places that is switched on.
if let Some(fb) = fake_borrows && let Ok(match_place_resolved) =
- match_place.clone().try_upvars_resolved(self)
+ match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
{
- let resolved_place = match_place_resolved.into_place(self);
+ let resolved_place = match_place_resolved.into_place(self.tcx, self.typeck_results);
fb.insert(resolved_place);
}
candidates = rest;
}
// at least the first candidate ought to be tested
- assert!(
- total_candidate_count > candidates.len(),
- "{}, {:#?}",
- total_candidate_count,
- candidates
- );
- debug!("tested_candidates: {}", total_candidate_count - candidates.len());
- debug!("untested_candidates: {}", candidates.len());
+ assert!(total_candidate_count > candidates.len());
+ debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len());
+ debug!("test_candidates: untested_candidates: {}", candidates.len());
// HACK(matthewjasper) This is a closure so that we can let the test
// create its blocks before the rest of the match. This currently
);
let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None;
let expr_place: Place<'tcx>;
- if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self) {
- expr_place = expr_builder.into_place(self);
+ if let Ok(expr_builder) =
+ expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
+ {
+ expr_place = expr_builder.into_place(self.tcx, self.typeck_results);
opt_expr_place = Some((Some(&expr_place), expr_span));
}
let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
/// first local is a binding for occurrences of `var` in the guard, which
/// will have type `&T`. The second local is a binding for occurrences of
/// `var` in the arm body, which will have type `T`.
- #[instrument(skip(self), level = "debug")]
fn declare_binding(
&mut self,
source_info: SourceInfo,
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
pat_span: Span,
) {
+ debug!(
+ "declare_binding(var_id={:?}, name={:?}, mode={:?}, var_ty={:?}, \
+ visibility_scope={:?}, source_info={:?})",
+ var_id, name, mode, var_ty, visibility_scope, source_info
+ );
+
let tcx = self.tcx;
let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
let binding_mode = match mode {
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability),
};
+ debug!("declare_binding: user_ty={:?}", user_ty);
let local = LocalDecl::<'tcx> {
mutability,
ty: var_ty,
} else {
LocalsForNode::One(for_arm_body)
};
- debug!(?locals);
+ debug!("declare_binding: vars={:?}", locals);
self.var_indices.insert(var_id, locals);
}
///
/// only generates a single switch. If this happens this method returns
/// `true`.
- #[instrument(skip(self, candidate), level = "debug")]
pub(super) fn simplify_candidate<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
) -> bool {
// repeatedly simplify match pairs until fixed point is reached
- debug!("{:#?}", candidate);
+ debug!(?candidate, "simplify_candidate");
// existing_bindings and new_bindings exists to keep the semantics in order.
// Reversing the binding order for bindings after `@` changes the binding order in places
ascription: thir::Ascription { ref annotation, variance },
} => {
// Apply the type ascription to the value at `match_pair.place`, which is the
- if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
+ if let Ok(place_resolved) =
+ match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+ {
candidate.ascriptions.push(Ascription {
annotation: annotation.clone(),
- source: place_resolved.into_place(self),
+ source: place_resolved.into_place(self.tcx, self.typeck_results),
variance,
});
}
ref subpattern,
is_primary: _,
} => {
- if let Ok(place_resolved) = match_pair.place.clone().try_upvars_resolved(self) {
+ if let Ok(place_resolved) =
+ match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+ {
candidate.bindings.push(Binding {
span: match_pair.pattern.span,
- source: place_resolved.into_place(self),
+ source: place_resolved.into_place(self.tcx, self.typeck_results),
var_id: var,
binding_mode: mode,
});
}
}
- #[instrument(skip(self, make_target_blocks, place_builder), level = "debug")]
pub(super) fn perform_test(
&mut self,
match_start_span: Span,
test: &Test<'tcx>,
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
) {
- let place = place_builder.into_place(self);
- let place_ty = place.ty(&self.local_decls, self.tcx);
- debug!(?place, ?place_ty,);
+ let place: Place<'tcx>;
+ if let Ok(test_place_builder) =
+ place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
+ {
+ place = test_place_builder.into_place(self.tcx, self.typeck_results);
+ } else {
+ return;
+ }
+ debug!(
+ "perform_test({:?}, {:?}: {:?}, {:?})",
+ block,
+ place,
+ place.ty(&self.local_decls, self.tcx),
+ test
+ );
let source_info = self.source_info(test.span);
match test.kind {
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
// we want to create a set of derived match-patterns like
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
- let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
+ let elem =
+ ProjectionElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index);
+ let downcast_place = match_pair.place.project(elem); // `(x as Variant)`
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
// e.g., `(x as Variant).0`
let place = downcast_place.clone().field(subpattern.field, subpattern.pattern.ty);
suffix: &'pat [Pat<'tcx>],
) {
let tcx = self.tcx;
- let (min_length, exact_size) =
- if let Ok(place_resolved) = place.clone().try_upvars_resolved(self) {
- match place_resolved.into_place(self).ty(&self.local_decls, tcx).ty.kind() {
- ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
- _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
- }
- } else {
- ((prefix.len() + suffix.len()).try_into().unwrap(), false)
- };
+ let (min_length, exact_size) = if let Ok(place_resolved) =
+ place.clone().try_upvars_resolved(tcx, self.typeck_results)
+ {
+ match place_resolved
+ .into_place(tcx, self.typeck_results)
+ .ty(&self.local_decls, tcx)
+ .ty
+ .kind()
+ {
+ ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
+ _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+ }
+ } else {
+ ((prefix.len() + suffix.len()).try_into().unwrap(), false)
+ };
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
let elem =
}
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
- pub(in crate::build) fn new(
+ pub(crate) fn new(
place: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>,
) -> MatchPair<'pat, 'tcx> {
- // Force the place type to the pattern's type.
- // FIXME(oli-obk): only do this when we don't already know the place type.
- // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
- let place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
MatchPair { place, pattern }
}
}
/// Convenience wrapper that pushes a scope and then executes `f`
/// to build its contents, popping the scope afterwards.
- #[instrument(skip(self, f), level = "debug")]
pub(crate) fn in_scope<F, R>(
&mut self,
region_scope: (region::Scope, SourceInfo),
where
F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
{
+ debug!("in_scope(region_scope={:?})", region_scope);
let source_scope = self.source_scope;
let tcx = self.tcx;
if let LintLevel::Explicit(current_hir_id) = lint_level {
let rv = unpack!(block = f(self));
unpack!(block = self.pop_scope(region_scope, block));
self.source_scope = source_scope;
- debug!(?block);
+ debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block);
block.and(rv)
}
_ => None,
};
- trace!(?expr.ty);
-
// Now apply adjustments, if any.
for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
trace!(?expr, ?adjustment);
self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span));
}
- trace!(?expr.ty, "after adjustments");
-
// Next, wrap this up in the expr's scope.
expr = Expr {
temp_lifetime,
/// Creates a new list of wildcard fields for a given constructor. The result must have a
/// length of `constructor.arity()`.
- #[instrument(level = "trace")]
- pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
+ pub(super) fn wildcards(
+ cx: &MatchCheckCtxt<'p, 'tcx>,
+ ty: Ty<'tcx>,
+ constructor: &Constructor<'tcx>,
+ ) -> Self {
let ret = match constructor {
- Single | Variant(_) => match pcx.ty.kind() {
- ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()),
- ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)),
+ Single | Variant(_) => match ty.kind() {
+ ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter()),
+ ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)),
ty::Adt(adt, substs) => {
if adt.is_box() {
// The only legal patterns of type `Box` (outside `std`) are `_` and box
// patterns. If we're here we can assume this is a box pattern.
- Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0)))
+ Fields::wildcards_from_tys(cx, once(substs.type_at(0)))
} else {
let variant = &adt.variant(constructor.variant_index_for_adt(*adt));
- let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant)
+ let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
.map(|(_, ty)| ty);
- Fields::wildcards_from_tys(pcx.cx, tys)
+ Fields::wildcards_from_tys(cx, tys)
}
}
- _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx),
+ _ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
},
- Slice(slice) => match *pcx.ty.kind() {
+ Slice(slice) => match *ty.kind() {
ty::Slice(ty) | ty::Array(ty, _) => {
let arity = slice.arity();
- Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty))
+ Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
}
- _ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
+ _ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
},
Str(..)
| FloatRange(..)
bug!("called `Fields::wildcards` on an `Or` ctor")
}
};
- debug!(?ret);
+ debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
ret
}
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
/// `Some(_)`.
pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
- let fields = Fields::wildcards(pcx, &ctor);
+ let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP)
}
/// `other_ctor` can be different from `self.ctor`, but must be covered by it.
pub(super) fn specialize<'a>(
&'a self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
+ cx: &MatchCheckCtxt<'p, 'tcx>,
other_ctor: &Constructor<'tcx>,
) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> {
match (&self.ctor, other_ctor) {
(Wildcard, _) => {
// We return a wildcard for each field of `other_ctor`.
- Fields::wildcards(pcx, other_ctor).iter_patterns().collect()
+ Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect()
}
(Slice(self_slice), Slice(other_slice))
if self_slice.arity() != other_slice.arity() =>
let prefix = &self.fields.fields[..prefix];
let suffix = &self.fields.fields[self_slice.arity() - suffix..];
let wildcard: &_ =
- pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
+ cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
let extra_wildcards = other_slice.arity() - self_slice.arity();
let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
prefix.iter().chain(extra_wildcards).chain(suffix).collect()
}
}
- #[instrument(skip(self), level = "debug")]
fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
let mut ty = self.typeck_results.node_type(pat.hir_id);
/// This is roughly the inverse of `Constructor::apply`.
fn pop_head_constructor(
&self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
+ cx: &MatchCheckCtxt<'p, 'tcx>,
ctor: &Constructor<'tcx>,
) -> PatStack<'p, 'tcx> {
// We pop the head pattern and push the new fields extracted from the arguments of
// `self.head()`.
- let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor);
+ let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor);
new_fields.extend_from_slice(&self.pats[1..]);
PatStack::from_vec(new_fields)
}
let mut matrix = Matrix::empty();
for row in &self.patterns {
if ctor.is_covered_by(pcx, row.head().ctor()) {
- let new_row = row.pop_head_constructor(pcx, ctor);
+ let new_row = row.pop_head_constructor(pcx.cx, ctor);
matrix.push(new_row);
}
}
is_under_guard: bool,
is_top_level: bool,
) -> Usefulness<'p, 'tcx> {
- debug!(?matrix, ?v);
+ debug!("matrix,v={:?}{:?}", matrix, v);
let Matrix { patterns: rows, .. } = matrix;
// The base case. We are pattern-matching on () and the return value is
debug_assert!(rows.iter().all(|r| r.len() == v.len()));
+ let ty = v.head().ty();
+ let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
+ debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
+ let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
+
// If the first pattern is an or-pattern, expand it.
let mut ret = Usefulness::new_not_useful(witness_preference);
if v.head().is_or_pat() {
}
}
} else {
- let mut ty = v.head().ty();
-
- // Opaque types can't get destructured/split, but the patterns can
- // actually hint at hidden types, so we use the patterns' types instead.
- if let ty::Opaque(..) = v.head().ty().kind() {
- if let Some(row) = rows.first() {
- ty = row.head().ty();
- }
- }
- let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
- debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
- let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
-
let v_ctor = v.head().ctor();
debug!(?v_ctor);
if let Constructor::IntRange(ctor_range) = &v_ctor {
debug!("specialize({:?})", ctor);
// We cache the result of `Fields::wildcards` because it is used a lot.
let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
- let v = v.pop_head_constructor(pcx, &ctor);
+ let v = v.pop_head_constructor(cx, &ctor);
let usefulness = ensure_sufficient_stack(|| {
is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
});
match *self {
ProjectionElem::Deref => ProjectionElem::Deref,
ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, ty.lift()),
- ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty.lift()),
ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()),
ProjectionElem::Subslice { from, to, from_end } => {
ProjectionElem::Subslice { from, to, from_end }
ProjectionElem::Field { .. } |
ProjectionElem::ConstantIndex { .. } |
ProjectionElem::Subslice { .. } |
- ProjectionElem::OpaqueCast { .. } |
ProjectionElem::Downcast { .. } => true,
}
})
true
}
- fn check_doc_tuple_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
+ fn check_doc_fake_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
match self.tcx.hir().find(hir_id).and_then(|node| match node {
hir::Node::Item(item) => Some(&item.kind),
_ => None,
}) {
Some(ItemKind::Impl(ref i)) => {
- if !matches!(&i.self_ty.kind, hir::TyKind::Tup([_])) {
- self.tcx.sess.emit_err(errors::DocTupleVariadicNotFirst { span: meta.span() });
+ let is_valid = matches!(&i.self_ty.kind, hir::TyKind::Tup([_]))
+ || if let hir::TyKind::BareFn(bare_fn_ty) = &i.self_ty.kind {
+ bare_fn_ty.decl.inputs.len() == 1
+ } else {
+ false
+ };
+ if !is_valid {
+ self.tcx.sess.emit_err(errors::DocFakeVariadicNotValid { span: meta.span() });
return false;
}
}
is_valid = false
}
- sym::tuple_variadic
- if !self.check_attr_not_crate_level(meta, hir_id, "tuple_variadic")
- || !self.check_doc_tuple_variadic(meta, hir_id) =>
+ sym::fake_variadic
+ if !self.check_attr_not_crate_level(meta, hir_id, "fake_variadic")
+ || !self.check_doc_fake_variadic(meta, hir_id) =>
{
is_valid = false
}
| sym::notable_trait
| sym::passes
| sym::plugins
- | sym::tuple_variadic => {}
+ | sym::fake_variadic => {}
sym::test => {
if !self.check_test_attr(meta, hir_id) {
}
#[derive(SessionDiagnostic)]
-#[error(passes::doc_tuple_variadic_not_first)]
-pub struct DocTupleVariadicNotFirst {
+#[error(passes::doc_fake_variadic_not_valid)]
+pub struct DocFakeVariadicNotValid {
#[primary_span]
pub span: Span,
}
-// Detecting lib features (i.e., features that are not lang features).
-//
-// These are declared using stability attributes (e.g., `#[stable (..)]`
-// and `#[unstable (..)]`), but are not declared in one single location
-// (unlike lang features), which means we need to collect them instead.
+//! Detecting lib features (i.e., features that are not lang features).
+//!
+//! These are declared using stability attributes (e.g., `#[stable (..)]` and `#[unstable (..)]`),
+//! but are not declared in one single location (unlike lang features), which means we need to
+//! collect them instead.
use rustc_ast::{Attribute, MetaItemKind};
use rustc_errors::struct_span_err;
fn collect_feature(&mut self, feature: Symbol, since: Option<Symbol>, span: Span) {
let already_in_stable = self.lib_features.stable.contains_key(&feature);
- let already_in_unstable = self.lib_features.unstable.contains(&feature);
+ let already_in_unstable = self.lib_features.unstable.contains_key(&feature);
match (since, already_in_stable, already_in_unstable) {
(Some(since), _, false) => {
- if let Some(prev_since) = self.lib_features.stable.get(&feature) {
+ if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) {
if *prev_since != since {
self.span_feature_error(
span,
}
}
- self.lib_features.stable.insert(feature, since);
+ self.lib_features.stable.insert(feature, (since, span));
}
(None, false, _) => {
- self.lib_features.unstable.insert(feature);
+ self.lib_features.unstable.insert(feature, span);
}
(Some(_), _, true) | (None, true, _) => {
self.span_feature_error(
//! propagating default levels lexically from parent to children ast nodes.
use attr::StabilityLevel;
-use rustc_attr::{self as attr, ConstStability, Stability};
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
-use rustc_errors::struct_span_err;
+use rustc_attr::{self as attr, ConstStability, Stability, Unstable};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
#[derive(PartialEq)]
enum AnnotationKind {
- // Annotation is required if not inherited from unstable parents
+ /// Annotation is required if not inherited from unstable parents.
Required,
- // Annotation is useless, reject it
+ /// Annotation is useless, reject it.
Prohibited,
- // Deprecation annotation is useless, reject it. (Stability attribute is still required.)
+ /// Deprecation annotation is useless, reject it. (Stability attribute is still required.)
DeprecationProhibited,
- // Annotation itself is useless, but it can be propagated to children
+ /// Annotation itself is useless, but it can be propagated to children.
Container,
}
}
}
-// A private tree-walker for producing an Index.
+/// A private tree-walker for producing an `Index`.
struct Annotator<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
index: &'a mut Index,
}
impl<'a, 'tcx> Annotator<'a, 'tcx> {
- // Determine the stability for a node based on its attributes and inherited
- // stability. The stability is recorded in the index and used as the parent.
- // If the node is a function, `fn_sig` is its signature
+ /// Determine the stability for a node based on its attributes and inherited stability. The
+ /// stability is recorded in the index and used as the parent. If the node is a function,
+ /// `fn_sig` is its signature.
fn annotate<F>(
&mut self,
def_id: LocalDefId,
}
}
+ if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab {
+ self.index.implications.insert(implied_by, feature);
+ }
+
self.index.stab_map.insert(def_id, stab);
stab
});
stab_map: Default::default(),
const_stab_map: Default::default(),
depr_map: Default::default(),
+ implications: Default::default(),
};
{
reason: Some(Symbol::intern(reason)),
issue: NonZeroU32::new(27812),
is_soft: false,
+ implied_by: None,
},
feature: sym::rustc_private,
};
*providers = Providers {
check_mod_unstable_api_usage,
stability_index,
+ stability_implications: |tcx, _| tcx.stability().implications.clone(),
lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
lookup_deprecation_entry: |tcx, id| {
remaining_lib_features.remove(&sym::libc);
remaining_lib_features.remove(&sym::test);
- let check_features = |remaining_lib_features: &mut FxIndexMap<_, _>, defined_features: &[_]| {
- for &(feature, since) in defined_features {
- if let Some(since) = since {
- if let Some(span) = remaining_lib_features.get(&feature) {
- // Warn if the user has enabled an already-stable lib feature.
- unnecessary_stable_feature_lint(tcx, *span, feature, since);
- }
- }
- remaining_lib_features.remove(&feature);
- if remaining_lib_features.is_empty() {
- break;
- }
- }
- };
-
// We always collect the lib features declared in the current crate, even if there are
// no unknown features, because the collection also does feature attribute validation.
- let local_defined_features = tcx.lib_features(()).to_vec();
- if !remaining_lib_features.is_empty() {
- check_features(&mut remaining_lib_features, &local_defined_features);
+ let local_defined_features = tcx.lib_features(());
+ let mut all_lib_features: FxHashMap<_, _> =
+ local_defined_features.to_vec().iter().map(|el| *el).collect();
+ let mut implications = tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE).clone();
+ for &cnum in tcx.crates(()) {
+ implications.extend(tcx.stability_implications(cnum));
+ all_lib_features.extend(tcx.defined_lib_features(cnum).iter().map(|el| *el));
+ }
- for &cnum in tcx.crates(()) {
+ // Check that every feature referenced by an `implied_by` exists (for features defined in the
+ // local crate).
+ for (implied_by, feature) in tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE) {
+ // Only `implied_by` needs to be checked, `feature` is guaranteed to exist.
+ if !all_lib_features.contains_key(implied_by) {
+ let span = local_defined_features
+ .stable
+ .get(feature)
+ .map(|(_, span)| span)
+ .or_else(|| local_defined_features.unstable.get(feature))
+ .expect("feature that implied another does not exist");
+ tcx.sess
+ .struct_span_err(
+ *span,
+ format!("feature `{implied_by}` implying `{feature}` does not exist"),
+ )
+ .emit();
+ }
+ }
+
+ if !remaining_lib_features.is_empty() {
+ for (feature, since) in all_lib_features.iter() {
+ if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) {
+ // Warn if the user has enabled an already-stable lib feature.
+ if let Some(implies) = implications.get(&feature) {
+ unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since);
+ } else {
+ unnecessary_stable_feature_lint(tcx, *span, *feature, *since);
+ }
+ }
+ remaining_lib_features.remove(&feature);
if remaining_lib_features.is_empty() {
break;
}
- check_features(&mut remaining_lib_features, tcx.defined_lib_features(cnum));
}
}
// don't lint about unused features. We should re-enable this one day!
}
+fn unnecessary_partially_stable_feature_lint(
+ tcx: TyCtxt<'_>,
+ span: Span,
+ feature: Symbol,
+ implies: Symbol,
+ since: Symbol,
+) {
+ tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
+ lint.build(&format!(
+ "the feature `{feature}` has been partially stabilized since {since} and is succeeded \
+ by the feature `{implies}`"
+ ))
+ .span_suggestion(
+ span,
+ &format!(
+ "if you are using features which are still unstable, change to using `{implies}`"
+ ),
+ implies,
+ Applicability::MaybeIncorrect,
+ )
+ .span_suggestion(
+ tcx.sess.source_map().span_extend_to_line(span),
+ "if you are using features which are now stable, remove this line",
+ "",
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ });
+}
+
fn unnecessary_stable_feature_lint(tcx: TyCtxt<'_>, span: Span, feature: Symbol, since: Symbol) {
tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
lint.build(&format!(
- "the feature `{}` has been stable since {} and no longer requires \
- an attribute to enable",
- feature, since
+ "the feature `{feature}` has been stable since {since} and no longer requires an \
+ attribute to enable",
))
.emit();
});
) {
let span = path.span;
if let Some(stability) = &ext.stability {
- if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level {
+ if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level
+ {
let feature = stability.feature;
- if !self.active_features.contains(&feature) && !span.allows_unstable(feature) {
+
+ let is_allowed = |feature| {
+ self.active_features.contains(&feature) || span.allows_unstable(feature)
+ };
+ let allowed_by_implication =
+ implied_by.map(|feature| is_allowed(feature)).unwrap_or(false);
+ if !is_allowed(feature) && !allowed_by_implication {
let lint_buffer = &mut self.lint_buffer;
let soft_handler =
|lint, span, msg: &_| lint_buffer.buffer_lint(lint, node_id, span, msg);
binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
"include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
(default: no)"),
+ box_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "emit noalias metadata for box (default: yes)"),
branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED],
"set options for branch target identification and pointer authentication on AArch64"),
cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
sp
}
+ /// Extends the given `Span` to contain the entire line it is on.
+ pub fn span_extend_to_line(&self, sp: Span) -> Span {
+ self.span_extend_to_prev_char(self.span_extend_to_next_char(sp, '\n', true), '\n', true)
+ }
+
/// Given a `Span`, tries to get a shorter span ending before the first occurrence of `char`
/// `c`.
pub fn span_until_char(&self, sp: Span, c: char) -> Span {
fabsf32,
fabsf64,
fadd_fast,
+ fake_variadic,
fdiv_fast,
feature,
fence,
impl_lint_pass,
impl_macros,
impl_trait_in_bindings,
+ implied_by,
import,
import_shadowing,
imported_main,
tuple,
tuple_from_req,
tuple_indexing,
- tuple_variadic,
two_phase,
ty,
type_alias_enum_variants,
// seems likely that they should eventually be merged into more
// general routines.
-use crate::infer::TyCtxtInferExt;
+use crate::infer::{DefiningAnchor, TyCtxtInferExt};
use crate::traits::{
FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
Unimplemented,
// Do the initial selection for the obligation. This yields the
// shallow result we are looking for -- that is, what specific impl.
- tcx.infer_ctxt().enter(|infcx| {
+ tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter(|infcx| {
+ //~^ HACK `Bubble` is required for
+ // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
let mut selcx = SelectionContext::new(&infcx);
let obligation_cause = ObligationCause::dummy();
// Opaque types may have gotten their hidden types constrained, but we can ignore them safely
// as they will get constrained elsewhere, too.
- let _opaque_types = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
debug!("Cache miss: {trait_ref:?} => {impl_source:?}");
Ok(&*tcx.arena.alloc(impl_source))
use rustc_hir::{ItemKind, Node, PathSegment};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
+use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_middle::hir::nested_filter;
};
let param_env = tcx.param_env(defining_use_anchor);
- tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).enter(move |infcx| {
- let ocx = ObligationCtxt::new(&infcx);
- let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
+ tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)).enter(
+ move |infcx| {
+ let ocx = ObligationCtxt::new(&infcx);
+ let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
- let misc_cause = traits::ObligationCause::misc(span, hir_id);
+ let misc_cause = traits::ObligationCause::misc(span, hir_id);
- match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
- Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
- Err(ty_err) => {
- tcx.sess.delay_span_bug(
- span,
- &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
- );
+ match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
+ Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok),
+ Err(ty_err) => {
+ tcx.sess.delay_span_bug(
+ span,
+ &format!("could not unify `{hidden_type}` with revealed type:\n{ty_err}"),
+ );
+ }
}
- }
- // Additionally require the hidden type to be well-formed with only the generics of the opaque type.
- // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
- // hidden type is well formed even without those bounds.
- let predicate =
- ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into())).to_predicate(tcx);
- ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
-
- // Check that all obligations are satisfied by the implementation's
- // version.
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- infcx.report_fulfillment_errors(&errors, None, false);
- }
-
- match origin {
- // Checked when type checking the function containing them.
- hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
- // Can have different predicates to their defining use
- hir::OpaqueTyOrigin::TyAlias => {
- let outlives_environment = OutlivesEnvironment::new(param_env);
- infcx.check_region_obligations_and_report_errors(
- defining_use_anchor,
- &outlives_environment,
- );
+ // Additionally require the hidden type to be well-formed with only the generics of the opaque type.
+ // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
+ // hidden type is well formed even without those bounds.
+ let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_type.into()))
+ .to_predicate(tcx);
+ ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate));
+
+ // Check that all obligations are satisfied by the implementation's
+ // version.
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
}
- }
-
- // Clean up after ourselves
- let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
- });
+ match origin {
+ // Checked when type checking the function containing them.
+ hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
+ // Can have different predicates to their defining use
+ hir::OpaqueTyOrigin::TyAlias => {
+ let outlives_environment = OutlivesEnvironment::new(param_env);
+ infcx.check_region_obligations_and_report_errors(
+ defining_use_anchor,
+ &outlives_environment,
+ );
+ }
+ }
+ // Clean up after ourselves
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+ },
+ );
}
fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
.map(|e| e.map_bound(|e| *e).transpose_tuple2())
.map(|(bound, span)| {
debug!(?bound);
+ // this is where opaque type is found
let concrete_ty_bound = bound.subst(tcx, rebased_substs);
debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
ocx.register_obligations(obligations);
ocx.register_obligation(obligation);
}
-
// Check that all obligations are satisfied by the implementation's
// version.
let errors = ocx.select_all_or_error();
use rustc_session::Session;
use rustc_span::symbol::Ident;
use rustc_span::{self, Span};
-use rustc_trait_selection::traits::{
- self, ObligationCauseCode, SelectionContext, StatementAsExpression,
-};
+use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
use std::iter;
use std::slice;
// If so, we might have just forgotten to wrap some args in a tuple.
if let Some(ty::Tuple(tys)) =
formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind())
+ // If the tuple is unit, we're not actually wrapping any arguments.
+ && !tys.is_empty()
&& provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
{
// Wrap up the N provided arguments starting at this position in a tuple.
&self.misc(sp),
&mut |err| {
if let Some(expected_ty) = expected.only_has_type(self) {
- self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
+ if !self.consider_removing_semicolon(blk, expected_ty, err) {
+ self.consider_returning_binding(blk, expected_ty, err);
+ }
if expected_ty == self.tcx.types.bool {
// If this is caused by a missing `let` in a `while let`,
// silence this redundant error, as we already emit E0070.
ty
}
- /// A common error is to add an extra semicolon:
- ///
- /// ```compile_fail,E0308
- /// fn foo() -> usize {
- /// 22;
- /// }
- /// ```
- ///
- /// This routine checks if the final statement in a block is an
- /// expression with an explicit semicolon whose type is compatible
- /// with `expected_ty`. If so, it suggests removing the semicolon.
- fn consider_hint_about_removing_semicolon(
- &self,
- blk: &'tcx hir::Block<'tcx>,
- expected_ty: Ty<'tcx>,
- err: &mut Diagnostic,
- ) {
- if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
- if let StatementAsExpression::NeedsBoxing = boxed {
- err.span_suggestion_verbose(
- span_semi,
- "consider removing this semicolon and boxing the expression",
- "",
- Applicability::HasPlaceholders,
- );
- } else {
- err.span_suggestion_short(
- span_semi,
- "remove this semicolon",
- "",
- Applicability::MachineApplicable,
- );
- }
- }
- }
-
fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id));
match node {
.flat_map(|a| a.args.iter())
{
if let hir::GenericArg::Type(hir_ty) = &arg {
- if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
- &hir_ty.kind
- {
- // Avoid ICE with associated types. As this is best
- // effort only, it's ok to ignore the case. It
- // would trigger in `is_send::<T::AssocType>();`
- // from `typeck-default-trait-impl-assoc-type.rs`.
- } else {
- let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty);
- let ty = self.resolve_vars_if_possible(ty);
- if ty == predicate.self_ty() {
- error.obligation.cause.span = hir_ty.span;
- }
+ let ty = self.resolve_vars_if_possible(
+ self.typeck_results.borrow().node_type(hir_ty.hir_id),
+ );
+ if ty == predicate.self_ty() {
+ error.obligation.cause.span = hir_ty.span;
}
}
}
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
use rustc_ast::util::parser::ExprPrecedence;
+use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind};
Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
};
use rustc_infer::infer::{self, TyCtxtInferExt};
-use rustc_infer::traits;
+use rustc_infer::traits::{self, StatementAsExpression};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
+use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty, TypeVisitable};
use rustc_span::symbol::sym;
use rustc_span::Span;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) {
);
}
}
+
+ /// A common error is to add an extra semicolon:
+ ///
+ /// ```compile_fail,E0308
+ /// fn foo() -> usize {
+ /// 22;
+ /// }
+ /// ```
+ ///
+ /// This routine checks if the final statement in a block is an
+ /// expression with an explicit semicolon whose type is compatible
+ /// with `expected_ty`. If so, it suggests removing the semicolon.
+ pub(crate) fn consider_removing_semicolon(
+ &self,
+ blk: &'tcx hir::Block<'tcx>,
+ expected_ty: Ty<'tcx>,
+ err: &mut Diagnostic,
+ ) -> bool {
+ if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
+ if let StatementAsExpression::NeedsBoxing = boxed {
+ err.span_suggestion_verbose(
+ span_semi,
+ "consider removing this semicolon and boxing the expression",
+ "",
+ Applicability::HasPlaceholders,
+ );
+ } else {
+ err.span_suggestion_short(
+ span_semi,
+ "remove this semicolon",
+ "",
+ Applicability::MachineApplicable,
+ );
+ }
+ true
+ } else {
+ false
+ }
+ }
+
+ pub(crate) fn consider_returning_binding(
+ &self,
+ blk: &'tcx hir::Block<'tcx>,
+ expected_ty: Ty<'tcx>,
+ err: &mut Diagnostic,
+ ) {
+ let mut shadowed = FxHashSet::default();
+ let mut candidate_idents = vec![];
+ let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
+ if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
+ && let Some(pat_ty) = self.typeck_results.borrow().node_type_opt(*hir_id)
+ {
+ let pat_ty = self.resolve_vars_if_possible(pat_ty);
+ if self.can_coerce(pat_ty, expected_ty)
+ && !(pat_ty, expected_ty).references_error()
+ && shadowed.insert(ident.name)
+ {
+ candidate_idents.push((*ident, pat_ty));
+ }
+ }
+ true
+ };
+
+ let hir = self.tcx.hir();
+ for stmt in blk.stmts.iter().rev() {
+ let StmtKind::Local(local) = &stmt.kind else { continue; };
+ local.pat.walk(&mut find_compatible_candidates);
+ }
+ match hir.find(hir.get_parent_node(blk.hir_id)) {
+ Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => {
+ match hir.find(hir.get_parent_node(*hir_id)) {
+ Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
+ pat.walk(&mut find_compatible_candidates);
+ }
+ Some(
+ hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
+ | hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(_, body),
+ ..
+ })
+ | hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
+ ..
+ })
+ | hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
+ ..
+ }),
+ ) => {
+ for param in hir.body(*body).params {
+ param.pat.walk(&mut find_compatible_candidates);
+ }
+ }
+ Some(hir::Node::Expr(hir::Expr {
+ kind:
+ hir::ExprKind::If(
+ hir::Expr { kind: hir::ExprKind::Let(let_), .. },
+ then_block,
+ _,
+ ),
+ ..
+ })) if then_block.hir_id == *hir_id => {
+ let_.pat.walk(&mut find_compatible_candidates);
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+
+ match &candidate_idents[..] {
+ [(ident, _ty)] => {
+ let sm = self.tcx.sess.source_map();
+ if let Some(stmt) = blk.stmts.last() {
+ let stmt_span = sm.stmt_span(stmt.span, blk.span);
+ let sugg = if sm.is_multiline(blk.span)
+ && let Some(spacing) = sm.indentation_before(stmt_span)
+ {
+ format!("\n{spacing}{ident}")
+ } else {
+ format!(" {ident}")
+ };
+ err.span_suggestion_verbose(
+ stmt_span.shrink_to_hi(),
+ format!("consider returning the local binding `{ident}`"),
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ } else {
+ let sugg = if sm.is_multiline(blk.span)
+ && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo())
+ {
+ format!("\n{spacing} {ident}\n{spacing}")
+ } else {
+ format!(" {ident} ")
+ };
+ let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
+ err.span_suggestion_verbose(
+ sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
+ format!("consider returning the local binding `{ident}`"),
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ values if (1..3).contains(&values.len()) => {
+ let spans = values.iter().map(|(ident, _)| ident.span).collect::<Vec<_>>();
+ err.span_note(spans, "consider returning one of these bindings");
+ }
+ _ => {}
+ }
+ }
}
let rm_borrow_msg = "remove the borrow to obtain an owned `String`";
let to_owned_msg = "create an owned `String` from a string reference";
- let string_type = self.tcx.get_diagnostic_item(sym::String);
- let is_std_string = |ty: Ty<'tcx>| match ty.ty_adt_def() {
- Some(ty_def) => Some(ty_def.did()) == string_type,
- None => false,
+ let is_std_string = |ty: Ty<'tcx>| {
+ ty.ty_adt_def()
+ .map_or(false, |ty_def| self.tcx.is_diagnostic_item(sym::String, ty_def.did()))
};
match (lhs_ty.kind(), rhs_ty.kind()) {
(&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str
- if (*l_ty.kind() == Str || is_std_string(l_ty)) && (
- *r_ty.kind() == Str || is_std_string(r_ty) ||
- &format!("{:?}", rhs_ty) == "&&str"
- ) =>
+ if (*l_ty.kind() == Str || is_std_string(l_ty))
+ && (*r_ty.kind() == Str
+ || is_std_string(r_ty)
+ || matches!(
+ r_ty.kind(), Ref(_, inner_ty, _) if *inner_ty.kind() == Str
+ )) =>
{
if let IsAssign::No = is_assign { // Do not supply this message if `&str += &str`
err.span_label(op.span, "`+` cannot be used to concatenate two `&str` strings");
| ty::RawPtr(_)
| ty::Ref(..)
| ty::Never
+ | ty::FnPtr(_)
| ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span),
- ty::FnPtr(_) | ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
+ ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
let mut err = struct_span_err!(
self.tcx.sess,
ty.span,
macro_rules! maybe_tuple_doc {
($a:ident @ #[$meta:meta] $item:item) => {
- #[doc(tuple_variadic)]
+ #[cfg_attr(not(bootstrap), doc(fake_variadic))]
#[doc = "This trait is implemented for tuples up to twelve items long."]
#[$meta]
$item
macro_rules! maybe_tuple_doc {
($a:ident @ #[$meta:meta] $item:item) => {
- #[doc(tuple_variadic)]
+ #[cfg_attr(not(bootstrap), doc(fake_variadic))]
#[doc = "This trait is implemented for tuples up to twelve items long."]
#[$meta]
$item
/// Create an integer value from its representation as a byte array in
/// big endian.
///
- #[doc = $to_xe_bytes_doc]
+ #[doc = $from_xe_bytes_doc]
///
/// # Examples
///
/// Create an integer value from its representation as a byte array in
/// little endian.
///
- #[doc = $to_xe_bytes_doc]
+ #[doc = $from_xe_bytes_doc]
///
/// # Examples
///
/// [`from_be_bytes`]: Self::from_be_bytes
/// [`from_le_bytes`]: Self::from_le_bytes
///
- #[doc = $to_xe_bytes_doc]
+ #[doc = $from_xe_bytes_doc]
///
/// # Examples
///
// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(tuple_variadic)]
+#[cfg_attr(not(bootstrap), doc(fake_variadic))]
/// This trait is implemented on arbitrary-length tuples.
impl<T: Clone> Clone for (T,) {
fn clone(&self) -> Self {
// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(tuple_variadic)]
+#[cfg_attr(not(bootstrap), doc(fake_variadic))]
/// This trait is implemented on arbitrary-length tuples.
impl<T: Copy> Copy for (T,) {
// empty
/// Note that all of this is not portable to platforms where function pointers and data pointers
/// have different sizes.
///
-/// ### Traits
+/// ### Trait implementations
///
-/// Function pointers implement the following traits:
+/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic
+/// function pointers of varying length. Note that this is a convenience notation to avoid
+/// repetitive documentation, not valid Rust syntax.
+///
+/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
+/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
+/// may change:
///
-/// * [`Clone`]
/// * [`PartialEq`]
/// * [`Eq`]
/// * [`PartialOrd`]
/// * [`Pointer`]
/// * [`Debug`]
///
+/// The following traits are implemented for function pointers with any number of arguments and
+/// any ABI. These traits have implementations that are automatically generated by the compiler,
+/// so are not limited by missing language features:
+///
+/// * [`Clone`]
+/// * [`Copy`]
+/// * [`Send`]
+/// * [`Sync`]
+/// * [`Unpin`]
+/// * [`UnwindSafe`]
+/// * [`RefUnwindSafe`]
+///
/// [`Hash`]: hash::Hash
/// [`Pointer`]: fmt::Pointer
+/// [`UnwindSafe`]: panic::UnwindSafe
+/// [`RefUnwindSafe`]: panic::RefUnwindSafe
///
-/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
-/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
-/// may change.
-///
-/// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe*
-/// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits
-/// are specially known to the compiler.
+/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
+/// these traits are specially known to the compiler.
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_fn {}
+
+// Required to make auto trait impls render.
+// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
+#[doc(hidden)]
+#[cfg(not(bootstrap))]
+impl<Ret, T> fn(T) -> Ret {}
+
+// Fake impl that's only really used for docs.
+#[cfg(doc)]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(bootstrap), doc(fake_variadic))]
+/// This trait is implemented on function pointers with any number of arguments.
+impl<Ret, T> Clone for fn(T) -> Ret {
+ fn clone(&self) -> Self {
+ loop {}
+ }
+}
+
+// Fake impl that's only really used for docs.
+#[cfg(doc)]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(bootstrap), doc(fake_variadic))]
+/// This trait is implemented on function pointers with any number of arguments.
+impl<Ret, T> Copy for fn(T) -> Ret {
+ // empty
+}
hashee.hash(into);
}
+// If this is a unary fn pointer, it adds a doc comment.
+// Otherwise, it hides the docs entirely.
+macro_rules! maybe_fnptr_doc {
+ (@ #[$meta:meta] $item:item) => {
+ #[doc(hidden)]
+ #[$meta]
+ $item
+ };
+ ($a:ident @ #[$meta:meta] $item:item) => {
+ #[cfg_attr(not(bootstrap), doc(fake_variadic))]
+ #[doc = "This trait is implemented for function pointers with up to twelve arguments."]
+ #[$meta]
+ $item
+ };
+ ($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => {
+ #[doc(hidden)]
+ #[$meta]
+ $item
+ };
+}
+
// FIXME(strict_provenance_magic): function pointers have buggy codegen that
// necessitates casting to a usize to get the backend to do the right thing.
// for now I will break AVR to silence *a billion* lints. We should probably
// Impls for function pointers
macro_rules! fnptr_impls_safety_abi {
($FnTy: ty, $($Arg: ident),*) => {
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<Ret, $($Arg),*> PartialEq for $FnTy {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- *self as usize == *other as usize
+ maybe_fnptr_doc! {
+ $($Arg)* @
+ #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ impl<Ret, $($Arg),*> PartialEq for $FnTy {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ *self as usize == *other as usize
+ }
}
}
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<Ret, $($Arg),*> Eq for $FnTy {}
+ maybe_fnptr_doc! {
+ $($Arg)* @
+ #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ impl<Ret, $($Arg),*> Eq for $FnTy {}
+ }
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<Ret, $($Arg),*> PartialOrd for $FnTy {
- #[inline]
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- (*self as usize).partial_cmp(&(*other as usize))
+ maybe_fnptr_doc! {
+ $($Arg)* @
+ #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ impl<Ret, $($Arg),*> PartialOrd for $FnTy {
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ (*self as usize).partial_cmp(&(*other as usize))
+ }
}
}
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<Ret, $($Arg),*> Ord for $FnTy {
- #[inline]
- fn cmp(&self, other: &Self) -> Ordering {
- (*self as usize).cmp(&(*other as usize))
+ maybe_fnptr_doc! {
+ $($Arg)* @
+ #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ impl<Ret, $($Arg),*> Ord for $FnTy {
+ #[inline]
+ fn cmp(&self, other: &Self) -> Ordering {
+ (*self as usize).cmp(&(*other as usize))
+ }
}
}
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<Ret, $($Arg),*> hash::Hash for $FnTy {
- fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
- state.write_usize(*self as usize)
+ maybe_fnptr_doc! {
+ $($Arg)* @
+ #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ impl<Ret, $($Arg),*> hash::Hash for $FnTy {
+ fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
+ state.write_usize(*self as usize)
+ }
}
}
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::pointer_fmt_inner(*self as usize, f)
+ maybe_fnptr_doc! {
+ $($Arg)* @
+ #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::pointer_fmt_inner(*self as usize, f)
+ }
}
}
- #[stable(feature = "fnptr_impls", since = "1.4.0")]
- impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::pointer_fmt_inner(*self as usize, f)
+ maybe_fnptr_doc! {
+ $($Arg)* @
+ #[stable(feature = "fnptr_impls", since = "1.4.0")]
+ impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::pointer_fmt_inner(*self as usize, f)
+ }
}
}
}
}
fnptr_impls_args! {}
-fnptr_impls_args! { A }
+fnptr_impls_args! { T }
fnptr_impls_args! { A, B }
fnptr_impls_args! { A, B, C }
fnptr_impls_args! { A, B, C, D }
// Otherwise, it hides the docs entirely.
macro_rules! maybe_tuple_doc {
($a:ident @ #[$meta:meta] $item:item) => {
- #[doc(tuple_variadic)]
+ #[cfg_attr(not(bootstrap), doc(fake_variadic))]
#[doc = "This trait is implemented for tuples up to twelve items long."]
#[$meta]
$item
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
cfg_if::cfg_if! {
- if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "netbsd")))] {
+ if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "watchos"), not(target_os = "netbsd")))] {
// ARM EHABI personality routine.
// https://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
//
|| target.contains("illumos")
|| target.contains("apple-darwin")
|| target.contains("apple-ios")
+ || target.contains("apple-watchos")
|| target.contains("uwp")
|| target.contains("windows")
|| target.contains("fuchsia")
entry.unwrap();
}
}
+
+/// Test the fallback for getting the metadata of files like hiberfil.sys that
+/// Windows holds a special lock on, preventing normal means of querying
+/// metadata. See #96980.
+///
+/// Note this fails in CI because `hiberfil.sys` does not actually exist there.
+/// Therefore it's marked as ignored.
+#[test]
+#[ignore]
+#[cfg(windows)]
+fn hiberfil_sys() {
+ let hiberfil = Path::new(r"C:\hiberfil.sys");
+ assert_eq!(true, hiberfil.try_exists().unwrap());
+ fs::symlink_metadata(hiberfil).unwrap();
+ fs::metadata(hiberfil).unwrap();
+ assert_eq!(true, hiberfil.exists());
+}
pub mod redox;
#[cfg(target_os = "solaris")]
pub mod solaris;
-
#[cfg(target_os = "solid_asp3")]
pub mod solid;
#[cfg(target_os = "vxworks")]
target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
+ target_os = "watchos",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
+ target_os = "watchos",
target_os = "netbsd",
target_os = "openbsd"
))]
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
+ target_os = "watchos",
target_os = "netbsd",
target_os = "openbsd"
))]
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
+ target_os = "watchos",
target_os = "netbsd",
target_os = "openbsd"
))]
))]
pub use self::impl_bsd::peer_cred;
-#[cfg(any(target_os = "macos", target_os = "ios",))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub use self::impl_mac::peer_cred;
#[cfg(any(target_os = "linux", target_os = "android"))]
}
}
-#[cfg(any(target_os = "macos", target_os = "ios",))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub mod impl_mac {
use super::UCred;
use crate::os::unix::io::AsRawFd;
target_os = "freebsd",
target_os = "ios",
target_os = "macos",
+ target_os = "watchos",
target_os = "openbsd"
))]
fn test_socket_pair() {
}
#[test]
-#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos",))]
+#[cfg(any(target_os = "linux", target_os = "ios", target_os = "macos", target_os = "watchos"))]
fn test_socket_pair_pids(arg: Type) -> RetType {
// Create two connected sockets and get their peer credentials.
let (sock_a, sock_b) = UnixStream::pair().unwrap();
// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(tuple_variadic)]
+#[cfg_attr(not(bootstrap), doc(fake_variadic))]
/// This trait is implemented on arbitrary-length tuples.
impl<T: Clone> Clone for (T,) {
fn clone(&self) -> Self {
// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(tuple_variadic)]
+#[cfg_attr(not(bootstrap), doc(fake_variadic))]
/// This trait is implemented on arbitrary-length tuples.
impl<T: Copy> Copy for (T,) {
// empty
/// Note that all of this is not portable to platforms where function pointers and data pointers
/// have different sizes.
///
-/// ### Traits
+/// ### Trait implementations
///
-/// Function pointers implement the following traits:
+/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic
+/// function pointers of varying length. Note that this is a convenience notation to avoid
+/// repetitive documentation, not valid Rust syntax.
+///
+/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
+/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
+/// may change:
///
-/// * [`Clone`]
/// * [`PartialEq`]
/// * [`Eq`]
/// * [`PartialOrd`]
/// * [`Pointer`]
/// * [`Debug`]
///
+/// The following traits are implemented for function pointers with any number of arguments and
+/// any ABI. These traits have implementations that are automatically generated by the compiler,
+/// so are not limited by missing language features:
+///
+/// * [`Clone`]
+/// * [`Copy`]
+/// * [`Send`]
+/// * [`Sync`]
+/// * [`Unpin`]
+/// * [`UnwindSafe`]
+/// * [`RefUnwindSafe`]
+///
/// [`Hash`]: hash::Hash
/// [`Pointer`]: fmt::Pointer
+/// [`UnwindSafe`]: panic::UnwindSafe
+/// [`RefUnwindSafe`]: panic::RefUnwindSafe
///
-/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
-/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
-/// may change.
-///
-/// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe*
-/// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits
-/// are specially known to the compiler.
+/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
+/// these traits are specially known to the compiler.
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_fn {}
+
+// Required to make auto trait impls render.
+// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
+#[doc(hidden)]
+#[cfg(not(bootstrap))]
+impl<Ret, T> fn(T) -> Ret {}
+
+// Fake impl that's only really used for docs.
+#[cfg(doc)]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(bootstrap), doc(fake_variadic))]
+/// This trait is implemented on function pointers with any number of arguments.
+impl<Ret, T> Clone for fn(T) -> Ret {
+ fn clone(&self) -> Self {
+ loop {}
+ }
+}
+
+// Fake impl that's only really used for docs.
+#[cfg(doc)]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(bootstrap), doc(fake_variadic))]
+/// This trait is implemented on function pointers with any number of arguments.
+impl<Ret, T> Copy for fn(T) -> Ret {
+ // empty
+}
}
}
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
mod imp {
use super::Args;
use crate::ffi::CStr;
// for i in (0..[args count])
// res.push([args objectAtIndex:i])
// res
- #[cfg(target_os = "ios")]
+ #[cfg(any(target_os = "ios", target_os = "watchos"))]
pub fn args() -> Args {
use crate::ffi::OsString;
use crate::mem;
pub const EXE_EXTENSION: &str = "";
}
+#[cfg(target_os = "watchos")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "watchos";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".dylib";
+ pub const DLL_EXTENSION: &str = "dylib";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
#[cfg(target_os = "freebsd")]
pub mod os {
pub const FAMILY: &str = "unix";
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
+ target_os = "watchos",
))]
const fn max_iov() -> usize {
libc::IOV_MAX as usize
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
- target_os = "horizon"
+ target_os = "horizon",
+ target_os = "watchos",
)))]
const fn max_iov() -> usize {
16 // The minimum value required by POSIX.
all(target_os = "linux", target_env = "gnu"),
target_os = "macos",
target_os = "ios",
+ target_os = "watchos",
))]
use crate::sys::weak::syscall;
#[cfg(target_os = "macos")]
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "watchos",
all(target_os = "linux", target_env = "gnu")
))]
use libc::c_char;
target_os = "freebsd",
target_os = "openbsd",
target_os = "macos",
- target_os = "ios"
+ target_os = "ios",
+ target_os = "watchos",
))]
pub fn created(&self) -> io::Result<SystemTime> {
Ok(SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64))
target_os = "freebsd",
target_os = "openbsd",
target_os = "macos",
- target_os = "ios"
+ target_os = "ios",
+ target_os = "watchos",
)))]
pub fn created(&self) -> io::Result<SystemTime> {
cfg_has_statx! {
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "watchos",
target_os = "linux",
target_os = "emscripten",
target_os = "android",
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "watchos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "freebsd",
#[cfg(not(any(
target_os = "macos",
target_os = "ios",
+ target_os = "watchos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "freebsd",
cvt_r(|| unsafe { os_fsync(self.as_raw_fd()) })?;
return Ok(());
- #[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
unsafe fn os_fsync(fd: c_int) -> c_int {
libc::fcntl(fd, libc::F_FULLFSYNC)
}
- #[cfg(not(any(target_os = "macos", target_os = "ios")))]
+ #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))]
unsafe fn os_fsync(fd: c_int) -> c_int {
libc::fsync(fd)
}
cvt_r(|| unsafe { os_datasync(self.as_raw_fd()) })?;
return Ok(());
- #[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fcntl(fd, libc::F_FULLFSYNC)
}
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
- target_os = "openbsd"
+ target_os = "openbsd",
+ target_os = "watchos",
)))]
unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fsync(fd)
target_os = "linux",
target_os = "android",
target_os = "macos",
- target_os = "ios"
+ target_os = "ios",
+ target_os = "watchos",
)))]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
let (mut reader, reader_metadata) = open_from(from)?;
}
}
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
use crate::sync::atomic::{AtomicBool, Ordering};
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "watchos",
target_os = "l4re",
target_os = "android",
target_os = "redox"
#[cfg(not(any(
target_os = "macos",
target_os = "ios",
+ target_os = "watchos",
target_os = "l4re",
target_os = "android",
target_os = "redox",
#[cfg(not(any(
target_os = "macos",
target_os = "ios",
+ target_os = "watchos",
target_os = "android",
target_os = "espidf",
target_os = "horizon"
#[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "watchos",
target_os = "android",
target_os = "espidf",
target_os = "horizon"
// The poll on Darwin doesn't set POLLNVAL for closed fds.
target_os = "macos",
target_os = "ios",
+ target_os = "watchos",
target_os = "redox",
target_os = "l4re",
target_os = "horizon",
// See #41582 and https://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
#[link(name = "resolv")]
extern "C" {}
- } else if #[cfg(target_os = "ios")] {
+ } else if #[cfg(any(target_os = "ios", target_os = "watchos"))] {
#[link(name = "System")]
#[link(name = "objc")]
#[link(name = "Security", kind = "framework")]
)]
#[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")]
#[cfg_attr(
- any(target_os = "macos", target_os = "ios", target_os = "freebsd"),
+ any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"),
link_name = "__error"
)]
#[cfg_attr(target_os = "haiku", link_name = "_errnop")]
}
}
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub fn current_exe() -> io::Result<PathBuf> {
unsafe {
let mut sz: u32 = 0;
#[cfg(any(
target_os = "android",
target_os = "ios",
+ target_os = "watchos",
target_os = "emscripten",
target_os = "redox",
target_os = "vxworks",
#[cfg(not(any(
target_os = "android",
target_os = "ios",
+ target_os = "watchos",
target_os = "emscripten",
target_os = "redox",
target_os = "vxworks",
unix,
not(target_os = "macos"),
not(target_os = "ios"),
+ not(target_os = "watchos"),
not(target_os = "openbsd"),
not(target_os = "freebsd"),
not(target_os = "netbsd"),
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox.
-#[cfg(target_os = "ios")]
+#[cfg(any(target_os = "ios", target_os = "watchos"))]
mod imp {
use crate::io;
use crate::ptr;
}
}
- #[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub fn set_name(name: &CStr) {
unsafe {
libc::pthread_setname_np(name.as_ptr());
) {
// Use the system clock on systems that do not support pthread_condattr_setclock.
// This unfortunately results in problems when the system time changes.
- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "espidf"))]
+ #[cfg(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "espidf"
+ ))]
let (now, dur) = {
use super::time::SystemTime;
use crate::cmp::min;
(now, dur)
};
// Use the monotonic clock on other systems.
- #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "espidf")))]
+ #[cfg(not(any(
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "watchos",
+ target_os = "espidf"
+ )))]
let (now, dur) = {
use super::time::Timespec;
if #[cfg(any(
target_os = "macos",
target_os = "ios",
+ target_os = "watchos",
target_os = "l4re",
target_os = "android",
target_os = "redox"
}
}
-#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
mod inner {
use crate::sync::atomic::{AtomicU64, Ordering};
use crate::sys::cvt;
}
}
-#[cfg(not(any(target_os = "macos", target_os = "ios")))]
+#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "watchos")))]
mod inner {
use crate::fmt;
use crate::mem::MaybeUninit;
}
pub fn metadata(&self) -> io::Result<FileAttr> {
- Ok(FileAttr {
- attributes: self.data.dwFileAttributes,
- creation_time: self.data.ftCreationTime,
- last_access_time: self.data.ftLastAccessTime,
- last_write_time: self.data.ftLastWriteTime,
- file_size: ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64),
- reparse_tag: if self.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
- // reserved unless this is a reparse point
- self.data.dwReserved0
- } else {
- 0
- },
- volume_serial_number: None,
- number_of_links: None,
- file_index: None,
- })
+ Ok(self.data.into())
}
}
self.file_index
}
}
+impl From<c::WIN32_FIND_DATAW> for FileAttr {
+ fn from(wfd: c::WIN32_FIND_DATAW) -> Self {
+ FileAttr {
+ attributes: wfd.dwFileAttributes,
+ creation_time: wfd.ftCreationTime,
+ last_access_time: wfd.ftLastAccessTime,
+ last_write_time: wfd.ftLastWriteTime,
+ file_size: ((wfd.nFileSizeHigh as u64) << 32) | (wfd.nFileSizeLow as u64),
+ reparse_tag: if wfd.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+ // reserved unless this is a reparse point
+ wfd.dwReserved0
+ } else {
+ 0
+ },
+ volume_serial_number: None,
+ number_of_links: None,
+ file_index: None,
+ }
+ }
+}
fn to_u64(ft: &c::FILETIME) -> u64 {
(ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32)
}
pub fn stat(path: &Path) -> io::Result<FileAttr> {
- let mut opts = OpenOptions::new();
- // No read or write permissions are necessary
- opts.access_mode(0);
- // This flag is so we can open directories too
- opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
- let file = File::open(path, &opts)?;
- file.file_attr()
+ metadata(path, ReparsePoint::Follow)
}
pub fn lstat(path: &Path) -> io::Result<FileAttr> {
+ metadata(path, ReparsePoint::Open)
+}
+
+#[repr(u32)]
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum ReparsePoint {
+ Follow = 0,
+ Open = c::FILE_FLAG_OPEN_REPARSE_POINT,
+}
+impl ReparsePoint {
+ fn as_flag(self) -> u32 {
+ self as u32
+ }
+}
+
+fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
let mut opts = OpenOptions::new();
// No read or write permissions are necessary
opts.access_mode(0);
- opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT);
- let file = File::open(path, &opts)?;
- file.file_attr()
+ opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | reparse.as_flag());
+
+ // Attempt to open the file normally.
+ // If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileW`.
+ // If the fallback fails for any reason we return the original error.
+ match File::open(path, &opts) {
+ Ok(file) => file.file_attr(),
+ Err(e) if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => {
+ // `ERROR_SHARING_VIOLATION` will almost never be returned.
+ // Usually if a file is locked you can still read some metadata.
+ // However, there are special system files, such as
+ // `C:\hiberfil.sys`, that are locked in a way that denies even that.
+ unsafe {
+ let path = maybe_verbatim(path)?;
+
+ // `FindFirstFileW` accepts wildcard file names.
+ // Fortunately wildcards are not valid file names and
+ // `ERROR_SHARING_VIOLATION` means the file exists (but is locked)
+ // therefore it's safe to assume the file name given does not
+ // include wildcards.
+ let mut wfd = mem::zeroed();
+ let handle = c::FindFirstFileW(path.as_ptr(), &mut wfd);
+
+ if handle == c::INVALID_HANDLE_VALUE {
+ // This can fail if the user does not have read access to the
+ // directory.
+ Err(e)
+ } else {
+ // We no longer need the find handle.
+ c::FindClose(handle);
+
+ // `FindFirstFileW` reads the cached file information from the
+ // directory. The downside is that this metadata may be outdated.
+ let attrs = FileAttr::from(wfd);
+ if reparse == ReparsePoint::Follow && attrs.file_type().is_symlink() {
+ Err(e)
+ } else {
+ Ok(attrs)
+ }
+ }
+ }
+ }
+ Err(e) => Err(e),
+ }
}
pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
cfg_if::cfg_if! {
if #[cfg(any(
target_os = "dragonfly", target_os = "freebsd",
- target_os = "ios", target_os = "macos",
+ target_os = "ios", target_os = "macos", target_os = "watchos",
target_os = "openbsd", target_os = "netbsd", target_os = "illumos",
target_os = "solaris", target_os = "haiku", target_os = "l4re"))] {
use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
#[cfg(target_arch = "x86_64")]
pub const unwinder_private_data_size: usize = 6;
-#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
+#[cfg(all(target_arch = "arm", not(any(target_os = "ios", target_os = "watchos"))))]
pub const unwinder_private_data_size: usize = 20;
-#[cfg(all(target_arch = "arm", target_os = "ios"))]
+#[cfg(all(target_arch = "arm", any(target_os = "ios", target_os = "watchos")))]
pub const unwinder_private_data_size: usize = 5;
#[cfg(all(target_arch = "aarch64", target_pointer_width = "64"))]
}
cfg_if::cfg_if! {
-if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))] {
+if #[cfg(any(target_os = "ios", target_os = "watchos", target_os = "netbsd", not(target_arch = "arm")))] {
// Not ARM EHABI
#[repr(C)]
#[derive(Copy, Clone, PartialEq)]
rustflags.arg("-Zunstable-options");
}
- // FIXME(Urgau): This a hack as it shouldn't be gated on stage 0 but until `rustc_llvm`
- // is made to work with `--check-cfg` which is currently not easly possible until cargo
- // get some support for setting `--check-cfg` within build script, it's the least invasive
- // hack that still let's us have cfg checking for the vast majority of the codebase.
- if stage != 0 {
- // Enable cfg checking of cargo features for everything but std and also enable cfg
- // checking of names and values.
- //
- // Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like
- // backtrace, core_simd, std_float, ...), those dependencies have their own
- // features but cargo isn't involved in the #[path] process and so cannot pass the
- // complete list of features, so for that reason we don't enable checking of
- // features for std crates.
- cargo.arg(if mode != Mode::Std {
- "-Zcheck-cfg=names,values,features"
- } else {
- "-Zcheck-cfg=names,values"
- });
+ // Enable cfg checking of cargo features for everything but std and also enable cfg
+ // checking of names and values.
+ //
+ // Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like
+ // backtrace, core_simd, std_float, ...), those dependencies have their own
+ // features but cargo isn't involved in the #[path] process and so cannot pass the
+ // complete list of features, so for that reason we don't enable checking of
+ // features for std crates.
+ cargo.arg(if mode != Mode::Std {
+ "-Zcheck-cfg=names,values,output,features"
+ } else {
+ "-Zcheck-cfg=names,values,output"
+ });
- // Add extra cfg not defined in/by rustc
- //
- // Note: Altrough it would seems that "-Zunstable-options" to `rustflags` is useless as
- // cargo would implicitly add it, it was discover that sometimes bootstrap only use
- // `rustflags` without `cargo` making it required.
- rustflags.arg("-Zunstable-options");
- for (restricted_mode, name, values) in EXTRA_CHECK_CFGS {
- if *restricted_mode == None || *restricted_mode == Some(mode) {
- // Creating a string of the values by concatenating each value:
- // ',"tvos","watchos"' or '' (nothing) when there are no values
- let values = match values {
- Some(values) => values
- .iter()
- .map(|val| [",", "\"", val, "\""])
- .flatten()
- .collect::<String>(),
- None => String::new(),
- };
- rustflags.arg(&format!("--check-cfg=values({name}{values})"));
- }
+ // Add extra cfg not defined in/by rustc
+ //
+ // Note: Altrough it would seems that "-Zunstable-options" to `rustflags` is useless as
+ // cargo would implicitly add it, it was discover that sometimes bootstrap only use
+ // `rustflags` without `cargo` making it required.
+ rustflags.arg("-Zunstable-options");
+ for (restricted_mode, name, values) in EXTRA_CHECK_CFGS {
+ if *restricted_mode == None || *restricted_mode == Some(mode) {
+ // Creating a string of the values by concatenating each value:
+ // ',"tvos","watchos"' or '' (nothing) when there are no values
+ let values = match values {
+ Some(values) => values
+ .iter()
+ .map(|val| [",", "\"", val, "\""])
+ .flatten()
+ .collect::<String>(),
+ None => String::new(),
+ };
+ rustflags.arg(&format!("--check-cfg=values({name}{values})"));
}
}
for_,
items: trait_items,
polarity,
- kind: if utils::has_doc_flag(tcx, did, sym::tuple_variadic) {
- ImplKind::TupleVaradic
+ kind: if utils::has_doc_flag(tcx, did, sym::fake_variadic) {
+ ImplKind::FakeVaradic
} else {
ImplKind::Normal
},
for_,
items,
polarity: tcx.impl_polarity(def_id),
- kind: if utils::has_doc_flag(tcx, def_id.to_def_id(), sym::tuple_variadic) {
- ImplKind::TupleVaradic
+ kind: if utils::has_doc_flag(tcx, def_id.to_def_id(), sym::fake_variadic) {
+ ImplKind::FakeVaradic
} else {
ImplKind::Normal
},
Reference => [RefSimplifiedType(Mutability::Not), RefSimplifiedType(Mutability::Mut)].into_iter().collect(),
// FIXME: This will be wrong if we ever add inherent impls
// for function pointers.
- Fn => ArrayVec::new(),
+ Fn => single(FunctionSimplifiedType(1)),
Never => single(NeverSimplifiedType),
}
})
pub(crate) enum ImplKind {
Normal,
Auto,
- TupleVaradic,
+ FakeVaradic,
Blanket(Box<Type>),
}
matches!(self, ImplKind::Blanket(_))
}
- pub(crate) fn is_tuple_variadic(&self) -> bool {
- matches!(self, ImplKind::TupleVaradic)
+ pub(crate) fn is_fake_variadic(&self) -> bool {
+ matches!(self, ImplKind::FakeVaradic)
}
pub(crate) fn as_blanket_ty(&self) -> Option<&Type> {
if let clean::Type::Tuple(types) = &self.for_ &&
let [clean::Type::Generic(name)] = &types[..] &&
- (self.kind.is_tuple_variadic() || self.kind.is_auto()) {
+ (self.kind.is_fake_variadic() || self.kind.is_auto())
+ {
// Hardcoded anchor library/core/src/primitive_docs.rs
// Link should match `# Trait implementations`
primitive_link_fragment(f, PrimitiveType::Tuple, &format!("({name}₁, {name}₂, …, {name}ₙ)"), "#trait-implementations-1", cx)?;
+ } else if let clean::BareFunction(bare_fn) = &self.for_ &&
+ let [clean::Argument { type_: clean::Type::Generic(name), .. }] = &bare_fn.decl.inputs.values[..] &&
+ (self.kind.is_fake_variadic() || self.kind.is_auto())
+ {
+ // Hardcoded anchor library/core/src/primitive_docs.rs
+ // Link should match `# Trait implementations`
+
+ let hrtb = bare_fn.print_hrtb_with_space(cx);
+ let unsafety = bare_fn.unsafety.print_with_space();
+ let abi = print_abi_with_space(bare_fn.abi);
+ if f.alternate() {
+ write!(
+ f,
+ "{hrtb:#}{unsafety}{abi:#}",
+ )?;
+ } else {
+ write!(
+ f,
+ "{hrtb}{unsafety}{abi}",
+ )?;
+ }
+ let ellipsis = if bare_fn.decl.c_variadic {
+ ", ..."
+ } else {
+ ""
+ };
+ primitive_link_fragment(f, PrimitiveType::Tuple, &format!("fn ({name}₁, {name}₂, …, {name}ₙ{ellipsis})"), "#trait-implementations-1", cx)?;
+ // Write output.
+ if let clean::FnRetTy::Return(ty) = &bare_fn.decl.output {
+ write!(f, " -> ")?;
+ fmt_type(ty, f, use_absolute, cx)?;
+ }
} else if let Some(ty) = self.kind.as_blanket_ty() {
fmt_type(ty, f, use_absolute, cx)?;
} else {
let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
// FIXME: use something like ImplKind in JSON?
let (synthetic, blanket_impl) = match kind {
- clean::ImplKind::Normal | clean::ImplKind::TupleVaradic => (false, None),
+ clean::ImplKind::Normal | clean::ImplKind::FakeVaradic => (false, None),
clean::ImplKind::Auto => (true, None),
clean::ImplKind::Blanket(ty) => (false, Some(*ty)),
};
--- /dev/null
+// compile-flags: -O -Z box-noalias=no
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @box_should_not_have_noalias_if_disabled(
+// CHECK-NOT: noalias
+#[no_mangle]
+pub fn box_should_not_have_noalias_if_disabled(_b: Box<u8>) {}
--- /dev/null
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @box_should_have_noalias_by_default(
+// CHECK: noalias
+#[no_mangle]
+pub fn box_should_have_noalias_by_default(_b: Box<u8>) {}
trait Mine {}
// This one is fine
-#[doc(tuple_variadic)]
+#[doc(fake_variadic)]
impl<T> Mine for (T,) {}
trait Mine2 {}
// This one is not
-#[doc(tuple_variadic)] //~ ERROR
+#[doc(fake_variadic)] //~ ERROR
impl<T, U> Mine for (T,U) {}
fn main() {}
-error: `#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity
+error: `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity
--> $DIR/tuple-variadic-check.rs:12:7
|
-LL | #[doc(tuple_variadic)]
- | ^^^^^^^^^^^^^^
+LL | #[doc(fake_variadic)]
+ | ^^^^^^^^^^^^^
error: aborting due to previous error
-Z asm-comments=val -- generate comments into the assembly (may change behavior) (default: no)
-Z assert-incr-state=val -- assert that the incremental cache is in given state: either `loaded` or `not-loaded`.
-Z binary-dep-depinfo=val -- include artifacts (sysroot, crate dependencies) used during compilation in dep-info (default: no)
+ -Z box-noalias=val -- emit noalias metadata for box (default: yes)
-Z branch-protection=val -- set options for branch target identification and pointer authentication on AArch64
-Z cf-protection=val -- instrument control-flow architecture protection
-Z cgu-partitioning-strategy=val -- the codegen unit partitioning strategy to use
// @has - '//h2[@id="trait-implementations-1"]' 'Trait implementations'
/// # Trait implementations
///
-/// This header is hard-coded in the HTML format linking for `#[doc(tuple_variadics)]`.
+/// This header is hard-coded in the HTML format linking for `#[doc(fake_variadics)]`.
/// To make sure it gets linked correctly, we need to make sure the hardcoded anchor
/// in the code matches what rustdoc generates for the header.
mod tuple_prim {}
// @has foo/trait.Foo.html
// @has - '//section[@id="impl-Foo-for-(T%2C)"]/h3' 'impl<T> Foo for (T₁, T₂, …, Tₙ)'
-#[doc(tuple_variadic)]
+#[doc(fake_variadic)]
impl<T> Foo for (T,) {}
pub trait Bar {}
// @has foo/trait.Bar.html
// @has - '//section[@id="impl-Bar-for-(U%2C)"]/h3' 'impl<U: Foo> Bar for (U₁, U₂, …, Uₙ)'
-#[doc(tuple_variadic)]
+#[doc(fake_variadic)]
impl<U: Foo> Bar for (U,) {}
--- /dev/null
+fn main() {
+ let f = |_: (), f: fn()| f;
+ let _f = f(main);
+ //~^ ERROR this function takes 2 arguments but 1 argument was supplied
+}
--- /dev/null
+error[E0057]: this function takes 2 arguments but 1 argument was supplied
+ --> $DIR/issue-99482.rs:3:14
+ |
+LL | let _f = f(main);
+ | ^ ---- an argument of type `()` is missing
+ |
+note: closure defined here
+ --> $DIR/issue-99482.rs:2:13
+ |
+LL | let f = |_: (), f: fn()| f;
+ | ^^^^^^^^^^^^^^^^
+help: provide the argument
+ |
+LL | let _f = f((), main);
+ | ~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0057`.
LL | | };
| |_________- enclosing `async` block
+error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
+ --> $DIR/async-block-control-flow-static-semantics.rs:26:39
+ |
+LL | let _: &dyn Future<Output = ()> = █
+ | ^^^^^^ expected `()`, found `u8`
+ |
+ = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`
+
error[E0308]: mismatched types
--> $DIR/async-block-control-flow-static-semantics.rs:21:58
|
| |_^ expected `u8`, found `()`
error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
- --> $DIR/async-block-control-flow-static-semantics.rs:26:39
+ --> $DIR/async-block-control-flow-static-semantics.rs:17:39
|
LL | let _: &dyn Future<Output = ()> = █
| ^^^^^^ expected `()`, found `u8`
| |
| implicitly returns `()` as its body has no tail or `return` expression
-error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
- --> $DIR/async-block-control-flow-static-semantics.rs:17:39
- |
-LL | let _: &dyn Future<Output = ()> = █
- | ^^^^^^ expected `()`, found `u8`
- |
- = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`
-
error[E0308]: mismatched types
--> $DIR/async-block-control-flow-static-semantics.rs:47:44
|
--- /dev/null
+// check-pass
+
+#![feature(adt_const_params)]
+#![allow(incomplete_features)]
+
+pub trait GetType<const N: &'static str> {
+ type Ty;
+ fn get(&self) -> &Self::Ty;
+}
+
+pub fn get_val<T>(value: &T) -> &T::Ty
+where
+ T: GetType<"hello">,
+{
+ value.get()
+}
+
+fn main() {}
// Empty struct.
struct Empty;
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for Empty {
#[inline]
fn clone(&self) -> Empty { *self }
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::marker::Copy for Empty { }
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Empty {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "Empty")
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::default::Default for Empty {
#[inline]
fn default() -> Empty { Empty {} }
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for Empty {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
}
impl ::core::marker::StructuralPartialEq for Empty {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Empty {
#[inline]
fn eq(&self, other: &Empty) -> bool { true }
}
impl ::core::marker::StructuralEq for Empty {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Empty {
#[inline]
#[doc(hidden)]
fn assert_receiver_is_total_eq(&self) -> () {}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for Empty {
#[inline]
fn partial_cmp(&self, other: &Empty)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for Empty {
#[inline]
fn cmp(&self, other: &Empty) -> ::core::cmp::Ordering {
y: u32,
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for Point {
#[inline]
fn clone(&self) -> Point {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::marker::Copy for Point { }
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Point {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "Point", "x",
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::default::Default for Point {
#[inline]
fn default() -> Point {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for Point {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.x, state);
}
impl ::core::marker::StructuralPartialEq for Point {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Point {
#[inline]
fn eq(&self, other: &Point) -> bool {
}
impl ::core::marker::StructuralEq for Point {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Point {
#[inline]
#[doc(hidden)]
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for Point {
#[inline]
fn partial_cmp(&self, other: &Point)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for Point {
#[inline]
fn cmp(&self, other: &Point) -> ::core::cmp::Ordering {
b8: u32,
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for Big {
#[inline]
fn clone(&self) -> Big {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Big {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::default::Default for Big {
#[inline]
fn default() -> Big {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for Big {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.b1, state);
}
impl ::core::marker::StructuralPartialEq for Big {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Big {
#[inline]
fn eq(&self, other: &Big) -> bool {
}
impl ::core::marker::StructuralEq for Big {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Big {
#[inline]
#[doc(hidden)]
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for Big {
#[inline]
fn partial_cmp(&self, other: &Big)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for Big {
#[inline]
fn cmp(&self, other: &Big) -> ::core::cmp::Ordering {
// A struct with an unsized field. Some derives are not usable in this case.
struct Unsized([u32]);
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Unsized {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Unsized",
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for Unsized {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.0, state)
}
impl ::core::marker::StructuralPartialEq for Unsized {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Unsized {
#[inline]
fn eq(&self, other: &Unsized) -> bool { self.0 == other.0 }
}
impl ::core::marker::StructuralEq for Unsized {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Unsized {
#[inline]
#[doc(hidden)]
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for Unsized {
#[inline]
fn partial_cmp(&self, other: &Unsized)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for Unsized {
#[inline]
fn cmp(&self, other: &Unsized) -> ::core::cmp::Ordering {
#[repr(packed)]
struct PackedCopy(u32);
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for PackedCopy {
#[inline]
fn clone(&self) -> PackedCopy {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::marker::Copy for PackedCopy { }
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for PackedCopy {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedCopy",
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::default::Default for PackedCopy {
#[inline]
fn default() -> PackedCopy {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for PackedCopy {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&{ self.0 }, state)
}
impl ::core::marker::StructuralPartialEq for PackedCopy {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for PackedCopy {
#[inline]
fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } }
}
impl ::core::marker::StructuralEq for PackedCopy {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for PackedCopy {
#[inline]
#[doc(hidden)]
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for PackedCopy {
#[inline]
fn partial_cmp(&self, other: &PackedCopy)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for PackedCopy {
#[inline]
fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering {
#[repr(packed)]
struct PackedNonCopy(u8);
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for PackedNonCopy {
#[inline]
fn clone(&self) -> PackedNonCopy {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for PackedNonCopy {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let Self(ref __self_0_0) = *self;
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::default::Default for PackedNonCopy {
#[inline]
fn default() -> PackedNonCopy {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for PackedNonCopy {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
let Self(ref __self_0_0) = *self;
}
impl ::core::marker::StructuralPartialEq for PackedNonCopy {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for PackedNonCopy {
#[inline]
fn eq(&self, other: &PackedNonCopy) -> bool {
}
impl ::core::marker::StructuralEq for PackedNonCopy {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for PackedNonCopy {
#[inline]
#[doc(hidden)]
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for PackedNonCopy {
#[inline]
fn partial_cmp(&self, other: &PackedNonCopy)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for PackedNonCopy {
#[inline]
fn cmp(&self, other: &PackedNonCopy) -> ::core::cmp::Ordering {
// An empty enum.
enum Enum0 {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for Enum0 {
#[inline]
fn clone(&self) -> Enum0 { *self }
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::marker::Copy for Enum0 { }
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Enum0 {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
unsafe { ::core::intrinsics::unreachable() }
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for Enum0 {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
unsafe { ::core::intrinsics::unreachable() }
}
impl ::core::marker::StructuralPartialEq for Enum0 {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Enum0 {
#[inline]
fn eq(&self, other: &Enum0) -> bool {
}
impl ::core::marker::StructuralEq for Enum0 {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Enum0 {
#[inline]
#[doc(hidden)]
fn assert_receiver_is_total_eq(&self) -> () {}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for Enum0 {
#[inline]
fn partial_cmp(&self, other: &Enum0)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for Enum0 {
#[inline]
fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering {
},
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for Enum1 {
#[inline]
fn clone(&self) -> Enum1 {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Enum1 {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for Enum1 {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
match self {
}
impl ::core::marker::StructuralPartialEq for Enum1 {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Enum1 {
#[inline]
fn eq(&self, other: &Enum1) -> bool {
}
impl ::core::marker::StructuralEq for Enum1 {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Enum1 {
#[inline]
#[doc(hidden)]
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for Enum1 {
#[inline]
fn partial_cmp(&self, other: &Enum1)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for Enum1 {
#[inline]
fn cmp(&self, other: &Enum1) -> ::core::cmp::Ordering {
A,
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for Fieldless1 {
#[inline]
fn clone(&self) -> Fieldless1 { Fieldless1::A }
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Fieldless1 {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f, "A")
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::default::Default for Fieldless1 {
#[inline]
fn default() -> Fieldless1 { Self::A }
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for Fieldless1 {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
}
impl ::core::marker::StructuralPartialEq for Fieldless1 {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Fieldless1 {
#[inline]
fn eq(&self, other: &Fieldless1) -> bool { true }
}
impl ::core::marker::StructuralEq for Fieldless1 {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Fieldless1 {
#[inline]
#[doc(hidden)]
fn assert_receiver_is_total_eq(&self) -> () {}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for Fieldless1 {
#[inline]
fn partial_cmp(&self, other: &Fieldless1)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for Fieldless1 {
#[inline]
fn cmp(&self, other: &Fieldless1) -> ::core::cmp::Ordering {
C,
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for Fieldless {
#[inline]
fn clone(&self) -> Fieldless { *self }
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::marker::Copy for Fieldless { }
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Fieldless {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::default::Default for Fieldless {
#[inline]
fn default() -> Fieldless { Self::A }
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for Fieldless {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
let __self_tag = ::core::intrinsics::discriminant_value(self);
}
impl ::core::marker::StructuralPartialEq for Fieldless {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Fieldless {
#[inline]
fn eq(&self, other: &Fieldless) -> bool {
}
impl ::core::marker::StructuralEq for Fieldless {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Fieldless {
#[inline]
#[doc(hidden)]
fn assert_receiver_is_total_eq(&self) -> () {}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for Fieldless {
#[inline]
fn partial_cmp(&self, other: &Fieldless)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for Fieldless {
#[inline]
fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering {
},
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for Mixed {
#[inline]
fn clone(&self) -> Mixed {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::marker::Copy for Mixed { }
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Mixed {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::default::Default for Mixed {
#[inline]
fn default() -> Mixed { Self::P }
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for Mixed {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
let __self_tag = ::core::intrinsics::discriminant_value(self);
}
impl ::core::marker::StructuralPartialEq for Mixed {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Mixed {
#[inline]
fn eq(&self, other: &Mixed) -> bool {
}
impl ::core::marker::StructuralEq for Mixed {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Mixed {
#[inline]
#[doc(hidden)]
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for Mixed {
#[inline]
fn partial_cmp(&self, other: &Mixed)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for Mixed {
#[inline]
fn cmp(&self, other: &Mixed) -> ::core::cmp::Ordering {
// for this enum.
enum Fielded { X(u32), Y(bool), Z(Option<i32>), }
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for Fielded {
#[inline]
fn clone(&self) -> Fielded {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::fmt::Debug for Fielded {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::hash::Hash for Fielded {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
let __self_tag = ::core::intrinsics::discriminant_value(self);
}
impl ::core::marker::StructuralPartialEq for Fielded {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialEq for Fielded {
#[inline]
fn eq(&self, other: &Fielded) -> bool {
}
impl ::core::marker::StructuralEq for Fielded {}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Eq for Fielded {
#[inline]
#[doc(hidden)]
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::PartialOrd for Fielded {
#[inline]
fn partial_cmp(&self, other: &Fielded)
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::cmp::Ord for Fielded {
#[inline]
fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering {
pub i: i32,
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::clone::Clone for Union {
#[inline]
fn clone(&self) -> Union {
}
}
#[automatically_derived]
-#[allow(unused_qualifications)]
impl ::core::marker::Copy for Union { }
-impl fn(u8) { //~ ERROR E0118
+impl<T> T { //~ ERROR E0118
fn get_state(&self) -> String {
String::new()
}
error[E0118]: no nominal type found for inherent implementation
- --> $DIR/E0118.rs:1:6
+ --> $DIR/E0118.rs:1:9
|
-LL | impl fn(u8) {
- | ^^^^^^ impl requires a nominal type
+LL | impl<T> T {
+ | ^ impl requires a nominal type
|
= note: either implement a trait on it or create a newtype to wrap it instead
impl *mut Foo {} //~ ERROR E0390
+impl fn(Foo) {} //~ ERROR E0390
+
fn main() {
}
|
= help: consider using an extension trait instead
-error: aborting due to previous error
+error[E0390]: cannot define inherent `impl` for primitive types
+ --> $DIR/E0390.rs:7:6
+ |
+LL | impl fn(Foo) {}
+ | ^^^^^^^
+ |
+ = help: consider using an extension trait instead
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0390`.
trait Mine {}
-#[doc(tuple_variadic)] //~ ERROR: `#[doc(tuple_variadic)]` is meant for internal use only
+#[doc(fake_variadic)] //~ ERROR: `#[doc(fake_variadic)]` is meant for internal use only
impl<T> Mine for (T,) {}
fn main() {}
= note: see issue #90418 <https://github.com/rust-lang/rust/issues/90418> for more information
= help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
-error[E0658]: `#[doc(tuple_variadic)]` is meant for internal use only
+error[E0658]: `#[doc(fake_variadic)]` is meant for internal use only
--> $DIR/feature-gate-rustdoc_internals.rs:7:1
|
-LL | #[doc(tuple_variadic)]
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #[doc(fake_variadic)]
+ | ^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #90418 <https://github.com/rust-lang/rust/issues/90418> for more information
= help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable
--- /dev/null
+// Check that we do not ICE when structurally comparing types with lifetimes present.
+// check-pass
+
+pub struct Record<'a> {
+ pub args: &'a [(usize, &'a str)],
+}
+
+mod a {
+ extern "Rust" {
+ fn foo<'a, 'b>(record: &'a super::Record<'b>);
+
+ fn bar<'a, 'b>(record: &'a super::Record<'b>);
+ }
+}
+
+mod b {
+ extern "Rust" {
+ fn foo<'a, 'b>(record: &'a super::Record<'b>);
+
+ fn bar<'a, 'b>(record: &'a super::Record<'b>);
+ }
+}
+
+fn main() {}
--- /dev/null
+use std::fmt::Display;
+
+fn main() {
+ test("hi", true);
+}
+
+fn test<T: Display>(t: T, recurse: bool) -> impl Display {
+ let f = || {
+ let i: u32 = test::<i32>(-1, false);
+ //~^ ERROR mismatched types
+ println!("{i}");
+ };
+ if recurse {
+ f();
+ }
+ t
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-99073-2.rs:9:22
+ |
+LL | fn test<T: Display>(t: T, recurse: bool) -> impl Display {
+ | ------------ the expected opaque type
+LL | let f = || {
+LL | let i: u32 = test::<i32>(-1, false);
+ | ^^^^^^^^^^^^^^^^^^^^^^ types differ
+ |
+ = note: expected opaque type `impl std::fmt::Display`
+ found type `u32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+fn main() {
+ let _ = fix(|_: &dyn Fn()| {});
+}
+
+fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
+ move || f(fix(&f))
+ //~^ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-99073.rs:6:13
+ |
+LL | fn fix<F: Fn(G), G: Fn()>(f: F) -> impl Fn() {
+ | --------- the expected opaque type
+LL | move || f(fix(&f))
+ | ^^^^^^^^^^ types differ
+ |
+ = note: expected opaque type `impl Fn()`
+ found type parameter `G`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
impl Foo for Concrete {
type Item = Concrete;
- //~^ mismatched types
+ //~^ type mismatch resolving
}
impl Bar for Concrete {
-error[E0308]: mismatched types
+error[E0271]: type mismatch resolving `<Concrete as Bar>::Other == Concrete`
--> $DIR/issue-99348-impl-compatibility.rs:8:17
|
LL | type Tait = impl Sized;
- | ---------- the expected opaque type
+ | ---------- the found opaque type
...
LL | type Item = Concrete;
- | ^^^^^^^^ types differ
+ | ^^^^^^^^ type mismatch resolving `<Concrete as Bar>::Other == Concrete`
|
- = note: expected opaque type `Tait`
- found struct `Concrete`
+note: expected this to be `Concrete`
+ --> $DIR/issue-99348-impl-compatibility.rs:13:18
+ |
+LL | type Other = Tait;
+ | ^^^^
+ = note: expected struct `Concrete`
+ found opaque type `Tait`
+note: required by a bound in `Foo::Item`
+ --> $DIR/issue-99348-impl-compatibility.rs:17:20
+ |
+LL | type Item: Bar<Other = Self>;
+ | ^^^^^^^^^^^^ required by this bound in `Foo::Item`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0271`.
= help: the trait `Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}`
= help: the following other types implement trait `Debug`:
extern "C" fn() -> Ret
- extern "C" fn(A) -> Ret
- extern "C" fn(A, ...) -> Ret
extern "C" fn(A, B) -> Ret
extern "C" fn(A, B, ...) -> Ret
extern "C" fn(A, B, C) -> Ret
extern "C" fn(A, B, C, ...) -> Ret
extern "C" fn(A, B, C, D) -> Ret
+ extern "C" fn(A, B, C, D, ...) -> Ret
+ extern "C" fn(A, B, C, D, E) -> Ret
and 68 others
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
| ^^^^ required by this bound in `assert_copy`
error[E0277]: the trait bound `Box<dyn Dummy>: Copy` is not satisfied
- --> $DIR/kindck-copy.rs:42:5
+ --> $DIR/kindck-copy.rs:42:19
|
LL | assert_copy::<Box<dyn Dummy>>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy>`
+ | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy>`
|
note: required by a bound in `assert_copy`
--> $DIR/kindck-copy.rs:5:18
| ^^^^ required by this bound in `assert_copy`
error[E0277]: the trait bound `Box<dyn Dummy + Send>: Copy` is not satisfied
- --> $DIR/kindck-copy.rs:43:5
+ --> $DIR/kindck-copy.rs:43:19
|
LL | assert_copy::<Box<dyn Dummy + Send>>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy + Send>`
+ | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<dyn Dummy + Send>`
|
note: required by a bound in `assert_copy`
--> $DIR/kindck-copy.rs:5:18
--- /dev/null
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(AddImpl)]
+// Unnecessary qualification `bar::foo`
+// https://github.com/rust-lang/rust/issues/71898
+pub fn derive(input: TokenStream) -> TokenStream {
+ "impl B {
+ fn foo(&self) { use bar::foo; bar::foo() }
+ }
+
+ fn foo() {}
+
+ mod bar { pub fn foo() {} }
+ ".parse().unwrap()
+}
--- /dev/null
+// run-pass
+// aux-build:add-impl.rs
+
+#![forbid(unused_qualifications)]
+
+#[macro_use]
+extern crate add_impl;
+
+#[derive(AddImpl)]
+struct B;
+
+fn main() {
+ B.foo();
+ foo();
+ bar::foo();
+}
| - ^^^^^ expected `isize`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
+ |
+help: consider returning the local binding `a`
+ |
+LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; a }
+ | +
error: aborting due to previous error
--- /dev/null
+#![feature(macro_metavar_expr)]
+
+macro_rules! metavar {
+ ( $i:expr ) => {
+ ${length(0)}
+ //~^ ERROR meta-variable expression `length` with depth parameter must be called inside of a macro repetition
+ };
+}
+
+const _: i32 = metavar!(0);
+
+fn main() {}
--- /dev/null
+error: meta-variable expression `length` with depth parameter must be called inside of a macro repetition
+ --> $DIR/meta-variable-depth-outside-repeat.rs:5:10
+ |
+LL | ${length(0)}
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
(
${count(foo, 0)},
${count(foo, 10)},
- //~^ ERROR count depth must be less than 4
+ //~^ ERROR depth parameter on meta-variable expression `count` must be less than 4
)
};
}
${ignore(foo)}
${index(0)},
${index(10)},
- //~^ ERROR index depth must be less than 3
+ //~^ ERROR depth parameter on meta-variable expression `index` must be less than 3
)* )* )*
)
};
${ignore(foo)}
${length(0)}
${length(10)}
- //~^ ERROR length depth must be less than 2
+ //~^ ERROR depth parameter on meta-variable expression `length` must be less than 2
)* )*
)
};
}
-
fn main() {
a!( { [ (a) ] [ (b c) ] } );
b!( { [ a b ] } );
- c!( { a } );
+ c!({ a });
}
-error: count depth must be less than 4
+error: depth parameter on meta-variable expression `count` must be less than 4
--> $DIR/out-of-bounds-arguments.rs:7:14
|
LL | ${count(foo, 10)},
| ^^^^^^^^^^^^^^^^
-error: index depth must be less than 3
+error: depth parameter on meta-variable expression `index` must be less than 3
--> $DIR/out-of-bounds-arguments.rs:19:18
|
LL | ${index(10)},
| ^^^^^^^^^^^
-error: length depth must be less than 2
+error: depth parameter on meta-variable expression `length` must be less than 2
--> $DIR/out-of-bounds-arguments.rs:32:18
|
LL | ${length(10)}
error[E0277]: the type `&mut i32` may not be safely transferred across an unwind boundary
- --> $DIR/not-panic-safe.rs:8:5
+ --> $DIR/not-panic-safe.rs:8:14
|
LL | assert::<&mut i32>();
- | ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary
+ | -^^^^^^^
+ | |
+ | `&mut i32` may not be safely transferred across an unwind boundary
+ | help: consider removing the leading `&`-reference
|
= help: the trait `UnwindSafe` is not implemented for `&mut i32`
= note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32`
struct Y;
impl X for Y {
async fn ft1() {} //~ ERROR functions in traits cannot be declared `async`
- //~^ ERROR impl has stricter requirements than trait
+ //~^ ERROR has an incompatible type for trait
unsafe fn ft2() {} // OK.
const fn ft3() {} //~ ERROR functions in traits cannot be declared const
extern "C" fn ft4() {}
//~| ERROR functions in traits cannot be declared const
//~| ERROR functions cannot be both `const` and `async`
//~| ERROR cycle detected
- //~| ERROR impl has stricter requirements than trait
+ //~| ERROR has an incompatible type for trait
}
impl Y {
LL | | }
| |_^
-error[E0276]: impl has stricter requirements than trait
- --> $DIR/fn-header-semantic-fail.rs:29:9
+error[E0053]: method `ft1` has an incompatible type for trait
+ --> $DIR/fn-header-semantic-fail.rs:29:24
|
-LL | async fn ft1();
- | --------------- definition of `ft1` from trait
-...
LL | async fn ft1() {}
- | ^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
+ | ^
+ | |
+ | checked the `Output` of this `async fn`, found opaque type
+ | expected `()`, found opaque type
+ |
+ = note: while checking the return type of the `async fn`
+note: type in trait
+ --> $DIR/fn-header-semantic-fail.rs:17:23
+ |
+LL | async fn ft1();
+ | ^
+ = note: expected fn pointer `fn()`
+ found fn pointer `fn() -> impl Future<Output = ()>`
-error[E0276]: impl has stricter requirements than trait
- --> $DIR/fn-header-semantic-fail.rs:34:9
+error[E0053]: method `ft5` has an incompatible type for trait
+ --> $DIR/fn-header-semantic-fail.rs:34:48
|
-LL | const async unsafe extern "C" fn ft5();
- | --------------------------------------- definition of `ft5` from trait
-...
LL | const async unsafe extern "C" fn ft5() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
+ | ^
+ | |
+ | checked the `Output` of this `async fn`, found opaque type
+ | expected `()`, found opaque type
+ |
+ = note: while checking the return type of the `async fn`
+note: type in trait
+ --> $DIR/fn-header-semantic-fail.rs:21:47
+ |
+LL | const async unsafe extern "C" fn ft5();
+ | ^
+ = note: expected fn pointer `unsafe extern "C" fn()`
+ found fn pointer `unsafe extern "C" fn() -> impl Future<Output = ()>`
error[E0391]: cycle detected when computing type of `main::<impl at $DIR/fn-header-semantic-fail.rs:28:5: 28:17>::ft5::{opaque#0}`
--> $DIR/fn-header-semantic-fail.rs:34:48
error: aborting due to 23 previous errors
-Some errors have detailed explanations: E0276, E0379, E0391, E0706.
-For more information about an error, try `rustc --explain E0276`.
+Some errors have detailed explanations: E0053, E0379, E0391, E0706.
+For more information about an error, try `rustc --explain E0053`.
| - ^^ expected `u8`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
+ |
+help: consider returning the local binding `a`
+ |
+LL | fn f(*, a: u8) -> u8 { a }
+ | +
error: aborting due to 2 previous errors
impl B for A {
async fn associated(); //~ ERROR without body
//~^ ERROR cannot be declared `async`
- //~| ERROR impl has stricter requirements than trait
+ //~| ERROR has an incompatible type for trait
}
fn main() {}
= note: `async` trait functions are not currently supported
= note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-error[E0276]: impl has stricter requirements than trait
- --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
+error[E0053]: method `associated` has an incompatible type for trait
+ --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:26
|
LL | async fn associated();
- | ---------------------- definition of `associated` from trait
-...
+ | ^
+ | |
+ | checked the `Output` of this `async fn`, found opaque type
+ | expected `()`, found opaque type
+ |
+ = note: while checking the return type of the `async fn`
+note: type in trait
+ --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:26
+ |
LL | async fn associated();
- | ^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `(): Future`
+ | ^
+ = note: expected fn pointer `fn()`
+ found fn pointer `fn() -> impl Future<Output = ()>`
error: aborting due to 6 previous errors
-Some errors have detailed explanations: E0276, E0706.
-For more information about an error, try `rustc --explain E0276`.
+Some errors have detailed explanations: E0053, E0706.
+For more information about an error, try `rustc --explain E0053`.
--- /dev/null
+#![feature(staged_api)]
+#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
+
+#[stable(feature = "foo", since = "1.62.0")]
+pub fn foo() {}
+
+#[unstable(feature = "foobar", issue = "1", implied_by = "foo")]
+pub fn foobar() {}
--- /dev/null
+#![feature(staged_api)]
+#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
+
+// Tests that `implied_by = "bar"` results in an error being emitted if `bar` does not exist.
+
+#[unstable(feature = "foobar", issue = "1", implied_by = "bar")]
+//~^ ERROR feature `bar` implying `foobar` does not exist
+pub fn foobar() {}
+
+fn main() {}
--- /dev/null
+error: feature `bar` implying `foobar` does not exist
+ --> $DIR/stability-attribute-implies-missing.rs:6:1
+ |
+LL | #[unstable(feature = "foobar", issue = "1", implied_by = "bar")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// aux-build:stability-attribute-implies.rs
+
+// Tests that despite the `foobar` feature being implied by now-stable feature `foo`, if `foobar`
+// isn't allowed in this crate then an error will be emitted.
+
+extern crate stability_attribute_implies;
+use stability_attribute_implies::{foo, foobar};
+//~^ ERROR use of unstable library feature 'foobar'
+
+fn main() {
+ foo(); // no error - stable
+ foobar(); //~ ERROR use of unstable library feature 'foobar'
+}
--- /dev/null
+error[E0658]: use of unstable library feature 'foobar'
+ --> $DIR/stability-attribute-implies-no-feature.rs:7:40
+ |
+LL | use stability_attribute_implies::{foo, foobar};
+ | ^^^^^^
+ |
+ = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
+ = help: add `#![feature(foobar)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'foobar'
+ --> $DIR/stability-attribute-implies-no-feature.rs:12:5
+ |
+LL | foobar();
+ | ^^^^^^
+ |
+ = note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
+ = help: add `#![feature(foobar)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// aux-build:stability-attribute-implies.rs
+#![deny(stable_features)]
+#![feature(foo)]
+//~^ ERROR the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+
+// Tests that the use of `implied_by` in the `#[unstable]` attribute results in a diagnostic
+// mentioning partial stabilization, and that given the implied unstable feature is unused (there
+// is no `foobar` call), that the compiler suggests removing the flag.
+
+extern crate stability_attribute_implies;
+use stability_attribute_implies::foo;
+
+fn main() {
+ foo();
+}
--- /dev/null
+error: the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+ --> $DIR/stability-attribute-implies-using-stable.rs:3:12
+ |
+LL | #![feature(foo)]
+ | ^^^
+ |
+note: the lint level is defined here
+ --> $DIR/stability-attribute-implies-using-stable.rs:2:9
+ |
+LL | #![deny(stable_features)]
+ | ^^^^^^^^^^^^^^^
+help: if you are using features which are still unstable, change to using `foobar`
+ |
+LL | #![feature(foobar)]
+ | ~~~~~~
+help: if you are using features which are now stable, remove this line
+ |
+LL - #![feature(foo)]
+ |
+
+error: aborting due to previous error
+
--- /dev/null
+// aux-build:stability-attribute-implies.rs
+#![deny(stable_features)]
+#![feature(foo)]
+//~^ ERROR the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+
+// Tests that the use of `implied_by` in the `#[unstable]` attribute results in a diagnostic
+// mentioning partial stabilization and that given the implied unstable feature is used (there is a
+// `foobar` call), that the compiler suggests changing to that feature and doesn't error about its
+// use.
+
+extern crate stability_attribute_implies;
+use stability_attribute_implies::{foo, foobar};
+
+fn main() {
+ foo();
+ foobar(); // no error!
+}
--- /dev/null
+error: the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
+ --> $DIR/stability-attribute-implies-using-unstable.rs:3:12
+ |
+LL | #![feature(foo)]
+ | ^^^
+ |
+note: the lint level is defined here
+ --> $DIR/stability-attribute-implies-using-unstable.rs:2:9
+ |
+LL | #![deny(stable_features)]
+ | ^^^^^^^^^^^^^^^
+help: if you are using features which are still unstable, change to using `foobar`
+ |
+LL | #![feature(foobar)]
+ | ~~~~~~
+help: if you are using features which are now stable, remove this line
+ |
+LL - #![feature(foo)]
+ |
+
+error: aborting due to previous error
+
--> $DIR/stability-attribute-sanity-2.rs:10:25
|
LL | #[stable(feature = "a", sinse = "1.0.0")]
- | ^^^^^^^^^^^^^^^ expected one of `since`, `note`
+ | ^^^^^^^^^^^^^^^ expected one of `feature`, `since`
error[E0545]: `issue` must be a non-zero numeric string or "none"
--> $DIR/stability-attribute-sanity-2.rs:13:27
--> $DIR/stability-attribute-sanity.rs:8:42
|
LL | #[stable(feature = "a", since = "b", reason)]
- | ^^^^^^ expected one of `since`, `note`
+ | ^^^^^^ expected one of `feature`, `since`
error[E0539]: incorrect meta item
--> $DIR/stability-attribute-sanity.rs:11:29
--- /dev/null
+fn a(i: i32) -> i32 {
+ //~^ ERROR mismatched types
+ let j = 2i32;
+}
+
+fn b(i: i32, j: i32) -> i32 {}
+//~^ ERROR mismatched types
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/return-bindings-multi.rs:1:17
+ |
+LL | fn a(i: i32) -> i32 {
+ | - ^^^ expected `i32`, found `()`
+ | |
+ | implicitly returns `()` as its body has no tail or `return` expression
+ |
+note: consider returning one of these bindings
+ --> $DIR/return-bindings-multi.rs:1:6
+ |
+LL | fn a(i: i32) -> i32 {
+ | ^
+LL |
+LL | let j = 2i32;
+ | ^
+
+error[E0308]: mismatched types
+ --> $DIR/return-bindings-multi.rs:6:25
+ |
+LL | fn b(i: i32, j: i32) -> i32 {}
+ | - ^^^ expected `i32`, found `()`
+ | |
+ | implicitly returns `()` as its body has no tail or `return` expression
+ |
+note: consider returning one of these bindings
+ --> $DIR/return-bindings-multi.rs:6:6
+ |
+LL | fn b(i: i32, j: i32) -> i32 {}
+ | ^ ^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-rustfix
+
+#![allow(unused)]
+
+fn a(i: i32) -> i32 { i }
+//~^ ERROR mismatched types
+
+fn b(opt_str: Option<String>) {
+ let s: String = if let Some(s) = opt_str {
+ s
+ //~^ ERROR mismatched types
+ } else {
+ String::new()
+ };
+}
+
+fn c() -> Option<i32> {
+ //~^ ERROR mismatched types
+ let x = Some(1);
+ x
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+#![allow(unused)]
+
+fn a(i: i32) -> i32 {}
+//~^ ERROR mismatched types
+
+fn b(opt_str: Option<String>) {
+ let s: String = if let Some(s) = opt_str {
+ //~^ ERROR mismatched types
+ } else {
+ String::new()
+ };
+}
+
+fn c() -> Option<i32> {
+ //~^ ERROR mismatched types
+ let x = Some(1);
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/return-bindings.rs:5:17
+ |
+LL | fn a(i: i32) -> i32 {}
+ | - ^^^ expected `i32`, found `()`
+ | |
+ | implicitly returns `()` as its body has no tail or `return` expression
+ |
+help: consider returning the local binding `i`
+ |
+LL | fn a(i: i32) -> i32 { i }
+ | +
+
+error[E0308]: mismatched types
+ --> $DIR/return-bindings.rs:9:46
+ |
+LL | let s: String = if let Some(s) = opt_str {
+ | ______________________________________________^
+LL | |
+LL | | } else {
+ | |_____^ expected struct `String`, found `()`
+ |
+help: consider returning the local binding `s`
+ |
+LL ~ let s: String = if let Some(s) = opt_str {
+LL + s
+LL ~
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/return-bindings.rs:16:11
+ |
+LL | fn c() -> Option<i32> {
+ | - ^^^^^^^^^^^ expected enum `Option`, found `()`
+ | |
+ | implicitly returns `()` as its body has no tail or `return` expression
+ |
+ = note: expected enum `Option<i32>`
+ found unit type `()`
+help: consider returning the local binding `x`
+ |
+LL ~ let x = Some(1);
+LL + x
+ |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
fn main() {
size_of_copy::<dyn Misc + Copy>();
//~^ ERROR only auto traits can be used as additional traits in a trait object
- //~| ERROR only auto traits can be used as additional traits in a trait object
//~| ERROR the trait bound `dyn Misc: Copy` is not satisfied
}
= help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
-error[E0225]: only auto traits can be used as additional traits in a trait object
- --> $DIR/issue-32963.rs:8:31
- |
-LL | size_of_copy::<dyn Misc + Copy>();
- | ---- ^^^^ additional non-auto trait
- | |
- | first non-auto trait
- |
- = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}`
- = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
-
error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied
- --> $DIR/issue-32963.rs:8:5
+ --> $DIR/issue-32963.rs:8:20
|
LL | size_of_copy::<dyn Misc + Copy>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
+ | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc`
|
note: required by a bound in `size_of_copy`
--> $DIR/issue-32963.rs:5:20
LL | fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
| ^^^^ required by this bound in `size_of_copy`
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
Some errors have detailed explanations: E0225, E0277.
For more information about an error, try `rustc --explain E0225`.
| ^ required by this bound in `std::mem::size_of`
error[E0277]: the size for values of type `[&U]` cannot be known at compilation time
- --> $DIR/suggest-where-clause.rs:31:5
+ --> $DIR/suggest-where-clause.rs:31:20
|
LL | mem::size_of::<[&U]>();
- | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ | ^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[&U]`
note: required by a bound in `std::mem::size_of`
// compile-flags: --edition=2021
-// check-pass
#![feature(type_alias_impl_trait)]
fn main() {
- type T = impl Copy;
+ type T = impl Copy; //~ ERROR unconstrained opaque type
let foo: T = (1u32, 2u32);
let (a, b): (u32, u32) = foo;
}
--- /dev/null
+error: unconstrained opaque type
+ --> $DIR/cross_inference_pattern_bug.rs:5:14
+ |
+LL | type T = impl Copy;
+ | ^^^^^^^^^
+ |
+ = note: `T` must be used in combination with a concrete type within the same module
+
+error: aborting due to previous error
+
+// known-bug: #96572
// compile-flags: --edition=2021 --crate-type=lib
// rustc-env:RUST_BACKTRACE=0
-// check-pass
// tracked in https://github.com/rust-lang/rust/issues/96572
#![feature(type_alias_impl_trait)]
fn main() {
- type T = impl Copy;
+ type T = impl Copy; // error: unconstrained opaque type
let foo: T = (1u32, 2u32);
- let (a, b) = foo; // this line used to make the code fail
+ let (a, b) = foo; // removing this line makes the code compile
}
--- /dev/null
+error: unconstrained opaque type
+ --> $DIR/cross_inference_pattern_bug_no_type.rs:10:14
+ |
+LL | type T = impl Copy; // error: unconstrained opaque type
+ | ^^^^^^^^^
+ |
+ = note: `T` must be used in combination with a concrete type within the same module
+
+error: aborting due to previous error
+
type Foo = impl Fn() -> Foo;
fn foo() -> Foo {
-//~^ ERROR: overflow evaluating the requirement `fn() -> Foo {foo}: Sized`
+//~^ ERROR: overflow evaluating the requirement
foo
}
-error[E0275]: overflow evaluating the requirement `fn() -> Foo {foo}: Sized`
+error[E0275]: overflow evaluating the requirement `<fn() -> Foo {foo} as FnOnce<()>>::Output == fn() -> Foo {foo}`
--> $DIR/issue-53398-cyclic-types.rs:5:13
|
LL | fn foo() -> Foo {
| ^^^
- |
- = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_53398_cyclic_types`)
error: aborting due to previous error
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+type X = impl Sized;
+
+trait Foo {
+ type Bar: Iterator<Item = X>;
+}
+
+impl Foo for () {
+ type Bar = std::vec::IntoIter<u32>;
+ //~^ ERROR type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X
+}
+
+fn incoherent() {
+ let f: X = 22_i32;
+}
+
+fn main() {}
--- /dev/null
+error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X`
+ --> $DIR/issue-57961.rs:10:16
+ |
+LL | type X = impl Sized;
+ | ---------- the expected opaque type
+...
+LL | type Bar = std::vec::IntoIter<u32>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found `u32`
+ |
+ = note: expected opaque type `X`
+ found type `u32`
+note: required by a bound in `Foo::Bar`
+ --> $DIR/issue-57961.rs:6:24
+ |
+LL | type Bar: Iterator<Item = X>;
+ | ^^^^^^^^ required by this bound in `Foo::Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
+++ /dev/null
-#![feature(type_alias_impl_trait)]
-
-fn main() {
- type T = impl Copy;
- let foo: T = Some((1u32, 2u32));
- match foo {
- None => (),
- Some((a, b, c)) => (), //~ ERROR mismatched types
- }
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-96572-unconstrained-mismatch.rs:8:14
- |
-LL | match foo {
- | --- this expression has type `T`
-LL | None => (),
-LL | Some((a, b, c)) => (),
- | ^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements
- |
- = note: expected tuple `(u32, u32)`
- found tuple `(_, _, _)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// check-pass
-
-#[allow(unconditional_recursion)]
-fn foo(b: bool) -> impl Copy {
- let (mut x, mut y) = foo(false);
- x = 42;
- y = "foo";
- if b {
- panic!()
- } else {
- foo(true)
- }
-}
-
-fn bar(b: bool) -> Option<impl Copy> {
- if b {
- return None;
- }
- match bar(!b) {
- Some((mut x, mut y)) => {
- x = 42;
- y = "foo";
- }
- None => {}
- }
- None
-}
-
-fn main() {}
+++ /dev/null
-#![feature(type_alias_impl_trait)]
-// check-pass
-
-type T = impl Copy;
-
-fn foo(foo: T) {
- let (mut x, mut y) = foo;
- x = 42;
- y = "foo";
-}
-
-type U = impl Copy;
-
-fn bar(bar: Option<U>) {
- match bar {
- Some((mut x, mut y)) => {
- x = 42;
- y = "foo";
- }
- None => {}
- }
-}
-
-fn main() {}
+++ /dev/null
-#![feature(type_alias_impl_trait)]
-// check-pass
-
-#[derive(Copy, Clone)]
-struct Foo((u32, u32));
-
-fn main() {
- type U = impl Copy;
- let foo: U = Foo((1u32, 2u32));
- let Foo((a, b)) = foo;
-}
+++ /dev/null
-#![feature(type_alias_impl_trait)]
-// check-pass
-
-fn main() {
- type T = impl Copy;
- let foo: T = Some((1u32, 2u32));
- let x = move || {
- match foo {
- None => (),
- Some((a, b)) => (),
- }
- };
-}
+++ /dev/null
-#![feature(type_alias_impl_trait)]
-// check-pass
-
-#[derive(Copy, Clone)]
-struct Foo((u32, u32));
-
-fn main() {
- type T = impl Copy;
- let foo: T = Foo((1u32, 2u32));
- let x = move || {
- let Foo((a, b)) = foo;
- };
-}
+++ /dev/null
-#![feature(type_alias_impl_trait)]
-// check-pass
-
-fn main() {
- type T = impl Copy;
- let foo: T = Some((1u32, 2u32));
- match foo {
- None => (),
- Some((a, b)) => (),
- }
-}
error[E0277]: `<T as Trait>::AssocType` cannot be sent between threads safely
- --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:5
+ --> $DIR/typeck-default-trait-impl-assoc-type.rs:11:15
|
LL | is_send::<T::AssocType>();
- | ^^^^^^^^^^^^^^^^^^^^^^^ `<T as Trait>::AssocType` cannot be sent between threads safely
+ | ^^^^^^^^^^^^ `<T as Trait>::AssocType` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `<T as Trait>::AssocType`
note: required by a bound in `is_send`
error[E0277]: the trait bound `dyn Foo<(isize,), isize, Output = ()>: Eq<dyn Foo<(isize,), Output = ()>>` is not satisfied
- --> $DIR/unboxed-closure-sugar-default.rs:21:5
+ --> $DIR/unboxed-closure-sugar-default.rs:21:10
|
LL | eq::<dyn Foo<(isize,), isize, Output=()>, dyn Foo(isize)>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq<dyn Foo<(isize,), Output = ()>>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq<dyn Foo<(isize,), Output = ()>>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>`
|
note: required by a bound in `eq`
--> $DIR/unboxed-closure-sugar-default.rs:14:40
// Errors expected:
eq::< dyn Foo<(),Output=()>,
dyn Foo(char) >();
- //~^^ ERROR E0277
+ //~^ ERROR E0277
}
fn main() { }
error[E0277]: the trait bound `dyn Foo<(char,), Output = ()>: Eq<dyn Foo<(), Output = ()>>` is not satisfied
- --> $DIR/unboxed-closure-sugar-equiv.rs:43:5
+ --> $DIR/unboxed-closure-sugar-equiv.rs:44:11
|
-LL | / eq::< dyn Foo<(),Output=()>,
-LL | | dyn Foo(char) >();
- | |_______________________________________________________________________^ the trait `Eq<dyn Foo<(), Output = ()>>` is not implemented for `dyn Foo<(char,), Output = ()>`
+LL | dyn Foo(char) >();
+ | ^^^^^^^^^^^^^ the trait `Eq<dyn Foo<(), Output = ()>>` is not implemented for `dyn Foo<(char,), Output = ()>`
|
note: required by a bound in `eq`
--> $DIR/unboxed-closure-sugar-equiv.rs:16:28
-Subproject commit 8827baaa781b37872134c1ba692a6f0aeb37890e
+Subproject commit d8d30a75376f78bb0fabe3d28ee9d87aa8035309
}
},
ProjectionElem::ConstantIndex { .. }
- | ProjectionElem::OpaqueCast(..)
| ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::Deref