///
/// ```
/// # #[allow(dead_code)]
+/// #[derive(Copy, Clone)]
/// struct Point {
/// x: i32,
/// y: i32,
/// the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy`
/// ```
///
+/// Shared references (`&T`) are also `Copy`, so a type can be `Copy`, even when it holds
+/// shared references of types `T` that are *not* `Copy`. Consider the following struct,
+/// which can implement `Copy`, because it only holds a *shared reference* to our non-`Copy`
+/// type `PointList` from above:
+///
+/// ```
+/// # #![allow(dead_code)]
+/// # struct PointList;
+/// #[derive(Copy, Clone)]
+/// struct PointListWrapper<'a> {
+/// point_list_ref: &'a PointList,
+/// }
+/// ```
+///
/// ## When *can't* my type be `Copy`?
///
/// Some types can't be copied safely. For example, copying `&mut T` would create an aliased
/// Swaps the values at two mutable locations, without deinitializing either one.
///
+/// * If you want to swap with a default or dummy value, see [`take`].
+/// * If you want to swap with a passed value, returning the old value, see [`replace`].
+///
/// # Examples
///
/// ```
/// assert_eq!(42, x);
/// assert_eq!(5, y);
/// ```
+///
+/// [`replace`]: fn.replace.html
+/// [`take`]: fn.take.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn swap<T>(x: &mut T, y: &mut T) {
/// Replaces `dest` with the default value of `T`, returning the previous `dest` value.
///
+/// * If you want to replace the values of two variables, see [`swap`].
+/// * If you want to replace with a passed value instead of the default value, see [`replace`].
+///
/// # Examples
///
/// A simple example:
/// ```
///
/// [`Clone`]: ../../std/clone/trait.Clone.html
+/// [`replace`]: fn.replace.html
+/// [`swap`]: fn.swap.html
#[inline]
#[stable(feature = "mem_take", since = "1.40.0")]
pub fn take<T: Default>(dest: &mut T) -> T {
///
/// Neither value is dropped.
///
+/// * If you want to replace the values of two variables, see [`swap`].
+/// * If you want to replace with a default value, see [`take`].
+///
/// # Examples
///
/// A simple example:
/// ```
///
/// [`Clone`]: ../../std/clone/trait.Clone.html
+/// [`swap`]: fn.swap.html
+/// [`take`]: fn.take.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use = "if you don't need the old value, you can just assign the new value directly"]
/// # Panics
///
/// Panics if `begin` does not point to the starting byte offset of
- /// a character (as defined by `is_char_boundary`), or if `begin >= len`.
+ /// a character (as defined by `is_char_boundary`), or if `begin > len`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
unsafe impl SliceIndex<str> for ops::RangeFrom<usize> {
type Output = str;
/// [Reference on "break expression"]: ../reference/expressions/loop-expr.html#break-expressions
/// [Reference on "break and loop values"]:
/// ../reference/expressions/loop-expr.html#break-and-loop-values
-///
mod break_keyword {}
#[doc(keyword = "const")]
/// For more information, take a look at the [Rust Book] or the [Reference]
///
/// [ADT]: https://en.wikipedia.org/wiki/Algebraic_data_type
-/// [`Option`]: option/enum.Option.html
/// [Rust Book]: ../book/ch06-01-defining-an-enum.html
/// [Reference]: ../reference/items/enumerations.html
mod enum_keyword {}
/// [`in`]: keyword.in.html
/// [`impl`]: keyword.impl.html
/// [higher-ranked trait bounds]: ../reference/trait-bounds.html#higher-ranked-trait-bounds
-/// [`IntoIterator`]: iter/trait.IntoIterator.html
/// [Rust book]:
/// ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for
/// [Reference]: ../reference/expressions/loop-expr.html#iterator-loops
/// For more information on the `move` keyword, see the [closure]'s section
/// of the Rust book or the [threads] section
///
-/// [`Fn` trait]: ../std/ops/trait.Fn.html
/// [closure]: ../book/ch13-01-closures.html
/// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads
mod move_keyword {}
/// [`extern`]: keyword.extern.html
/// [`mut`]: keyword.mut.html
/// [`unsafe`]: keyword.unsafe.html
-/// [`drop`]: mem/fn.drop.html
-/// [`Sync`]: marker/trait.Sync.html
-/// [`RefCell`]: cell/struct.RefCell.html
+/// [`RefCell`]: cell::RefCell
/// [Reference]: ../reference/items/static-items.html
mod static_keyword {}
/// For more information on structs, take a look at the [Rust Book][book] or the
/// [Reference][reference].
///
-/// [`PhantomData`]: marker/struct.PhantomData.html
+/// [`PhantomData`]: marker::PhantomData
/// [book]: ../book/ch05-01-defining-structs.html
/// [reference]: ../reference/items/structs.html
mod struct_keyword {}
/// [`for`]: keyword.for.html
/// [`impl`]: keyword.impl.html
/// [`unsafe`]: keyword.unsafe.html
-/// [`Send`]: marker/trait.Send.html
-/// [`Sync`]: marker/trait.Sync.html
/// [Ref-Traits]: ../reference/items/traits.html
/// [Ref-Trait-Objects]: ../reference/types/trait-object.html
mod trait_keyword {}
/// [`while`]: keyword.while.html
/// [`match`]: ../reference/expressions/match-expr.html#match-guards
/// [`false`]: keyword.false.html
-/// [`bool`]: primitive.bool.html
mod true_keyword {}
#[doc(keyword = "type")]
/// [`static`]: keyword.static.html
/// [`union`]: keyword.union.html
/// [`impl`]: keyword.impl.html
-/// [Send]: marker/trait.Send.html
-/// [Sync]: marker/trait.Sync.html
-/// [`Vec::set_len`]: vec/struct.Vec.html#method.set_len
/// [raw pointers]: ../reference/types/pointer.html
/// [memory safety]: ../book/ch19-01-unsafe-rust.html
/// [Rustnomicon]: ../nomicon/index.html
///
/// It is available for use in stable rust from version 1.39 onwards.
///
-/// [`Future`]: ./future/trait.Future.html
+/// [`Future`]: future::Future
/// [async book]: https://rust-lang.github.io/async-book/
mod async_keyword {}
///
/// It is available for use in stable rust from version 1.39 onwards.
///
-/// [`Future`]: ./future/trait.Future.html
+/// [`Future`]: future::Future
/// [async book]: https://rust-lang.github.io/async-book/
mod await_keyword {}
use crate::sys::platform::fs::MetadataExt as UnixMetadataExt;
use crate::sys_common::{AsInner, AsInnerMut, FromInner};
-/// Unix-specific extensions to [`File`].
-///
-/// [`File`]: ../../../../std/fs/struct.File.html
+/// Unix-specific extensions to [`fs::File`].
#[stable(feature = "file_offset", since = "1.15.0")]
pub trait FileExt {
/// Reads a number of bytes starting from a given offset.
///
/// The current file cursor is not affected by this function.
///
- /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
+ /// Similar to [`io::Read::read_exact`] but uses [`read_at`] instead of `read`.
///
- /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact
- /// [`read_at`]: #tymethod.read_at
+ /// [`read_at`]: FileExt::read_at
///
/// # Errors
///
/// If this function encounters an error of the kind
- /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+ /// [`io::ErrorKind::Interrupted`] then the error is ignored and the operation
/// will continue.
///
/// If this function encounters an "end of file" before completely filling
- /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
+ /// the buffer, it returns an error of the kind [`io::ErrorKind::UnexpectedEof`].
/// The contents of `buf` are unspecified in this case.
///
/// If any other read error is encountered then this function immediately
/// has read, but it will never read more than would be necessary to
/// completely fill the buffer.
///
- /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
- /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
- ///
/// # Examples
///
/// ```no_run
/// The current file cursor is not affected by this function.
///
/// This method will continuously call [`write_at`] until there is no more data
- /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+ /// to be written or an error of non-[`io::ErrorKind::Interrupted`] kind is
/// returned. This method will not return until the entire buffer has been
/// successfully written or such an error occurs. The first error that is
- /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+ /// not of [`io::ErrorKind::Interrupted`] kind generated from this method will be
/// returned.
///
/// # Errors
///
/// This function will return the first error of
- /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
+ /// non-[`io::ErrorKind::Interrupted`] kind that [`write_at`] returns.
///
- /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
- /// [`write_at`]: #tymethod.write_at
+ /// [`write_at`]: FileExt::write_at
///
/// # Examples
///
}
/// Unix-specific extensions to [`fs::Permissions`].
-///
-/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
/// Returns the underlying raw `st_mode` bits that contain the standard
}
/// Unix-specific extensions to [`fs::OpenOptions`].
-///
-/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait OpenOptionsExt {
/// Sets the mode bits that a new file will be created with.
}
/// Unix-specific extensions to [`fs::Metadata`].
-///
-/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Returns the ID of the device containing the file.
fn atime(&self) -> i64;
/// Returns the last access time of the file, in nanoseconds since [`atime`].
///
- /// [`atime`]: #tymethod.atime
+ /// [`atime`]: MetadataExt::atime
///
/// # Examples
///
fn mtime(&self) -> i64;
/// Returns the last modification time of the file, in nanoseconds since [`mtime`].
///
- /// [`mtime`]: #tymethod.mtime
+ /// [`mtime`]: MetadataExt::mtime
///
/// # Examples
///
fn ctime(&self) -> i64;
/// Returns the last status change time of the file, in nanoseconds since [`ctime`].
///
- /// [`ctime`]: #tymethod.ctime
+ /// [`ctime`]: MetadataExt::ctime
///
/// # Examples
///
}
}
-/// Unix-specific extensions for [`FileType`].
+/// Unix-specific extensions for [`fs::FileType`].
///
/// Adds support for special Unix file types such as block/character devices,
/// pipes, and sockets.
-///
-/// [`FileType`]: ../../../../std/fs/struct.FileType.html
#[stable(feature = "file_type_ext", since = "1.5.0")]
pub trait FileTypeExt {
/// Returns `true` if this file type is a block device.
}
/// Unix-specific extension methods for [`fs::DirEntry`].
-///
-/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
pub trait DirEntryExt {
/// Returns the underlying `d_ino` field in the contained `dirent`
}
/// Unix-specific extensions to [`fs::DirBuilder`].
-///
-/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
#[stable(feature = "dir_builder", since = "1.6.0")]
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
/// method.
///
- /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
- /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
- /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read
- /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ /// [`read`]: io::Read::read
///
/// # Examples
///
/// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
/// passed to this method.
///
- /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
- /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
- /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write
- /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ /// [`read`]: io::Read::read
///
/// # Examples
///
/// specified portions to immediately return with an appropriate value
/// (see the documentation of [`Shutdown`]).
///
- /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
- ///
/// # Examples
///
/// ```no_run
/// is established. When established, the corresponding [`UnixStream`] and
/// the remote peer's address will be returned.
///
- /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
+ /// [`UnixStream`]: crate::os::unix::net::UnixStream
///
/// # Examples
///
/// Ok(())
/// }
/// ```
- ///
- /// [`io::ErrorKind::WouldBlock`]: ../../../io/enum.ErrorKind.html#variant.WouldBlock
#[stable(feature = "unix_socket", since = "1.10.0")]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
self.0.set_nonblocking(nonblocking)
/// The iterator will never return [`None`] and will also not yield the
/// peer's [`SocketAddr`] structure.
///
- /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
- /// [`SocketAddr`]: struct.SocketAddr.html
- ///
/// # Examples
///
/// ```no_run
///
/// It will never return [`None`].
///
-/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
-/// [`UnixListener`]: struct.UnixListener.html
-///
/// # Examples
///
/// ```no_run
/// The [`send`] method may be used to send data to the specified address.
/// [`recv`] and [`recv_from`] will only receive data from that address.
///
- /// [`send`]: #method.send
- /// [`recv`]: #method.recv
- /// [`recv_from`]: #method.recv_from
+ /// [`send`]: UnixDatagram::send
+ /// [`recv`]: UnixDatagram::recv
+ /// [`recv_from`]: UnixDatagram::recv_from
///
/// # Examples
///
///
/// The [`connect`] method will connect the socket to a peer.
///
- /// [`connect`]: #method.connect
+ /// [`connect`]: UnixDatagram::connect
///
/// # Examples
///
/// block indefinitely. An [`Err`] is returned if the zero [`Duration`]
/// is passed to this method.
///
- /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
- /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
- /// [`recv`]: #method.recv
- /// [`recv_from`]: #method.recv_from
- /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ /// [`recv`]: UnixDatagram::recv
+ /// [`recv_from`]: UnixDatagram::recv_from
///
/// # Examples
///
/// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
/// method.
///
- /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
- /// [`send`]: #method.send
- /// [`send_to`]: #method.send_to
- /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ /// [`send`]: UnixDatagram::send
+ /// [`send_to`]: UnixDatagram::send_to
///
/// # Examples
///
/// specified portions to immediately return with an appropriate value
/// (see the documentation of [`Shutdown`]).
///
- /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
- ///
/// ```no_run
/// use std::os::unix::net::UnixDatagram;
/// use std::net::Shutdown;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
/// Unix-specific extensions to the [`process::Command`] builder.
-///
-/// [`process::Command`]: ../../../../std/process/struct.Command.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait CommandExt {
/// Sets the child process's user ID. This translates to a
/// This method is stable and usable, but it should be unsafe. To fix
/// that, it got deprecated in favor of the unsafe [`pre_exec`].
///
- /// [`pre_exec`]: #tymethod.pre_exec
+ /// [`pre_exec`]: CommandExt::pre_exec
#[stable(feature = "process_exec", since = "1.15.0")]
#[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
fn before_exec<F>(&mut self, f: F) -> &mut process::Command
/// a new child. Like spawn, however, the default behavior for the stdio
/// descriptors will be to inherited from the current process.
///
- /// [`process::exit`]: ../../../process/fn.exit.html
- ///
/// # Notes
///
/// The process may be in a "broken state" if this function returns in
}
/// Unix-specific extensions to [`process::ExitStatus`].
-///
-/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExitStatusExt {
/// Creates a new `ExitStatus` from the raw underlying `i32` return value of
#[allow(deprecated)]
pub type RawPthread = pthread_t;
-/// Unix-specific extensions to [`thread::JoinHandle`].
-///
-/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
+/// Unix-specific extensions to [`JoinHandle`].
#[stable(feature = "thread_extensions", since = "1.9.0")]
pub trait JoinHandleExt {
/// Extracts the raw pthread_t without taking ownership
use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust::{self, expr_to_string};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
use rustc_feature::{GateIssue, Stability};
b: Ty<'tcx>,
ckind: CItemKind,
) -> bool {
- debug!("structurally_same_type(cx, a = {:?}, b = {:?})", a, b);
- let tcx = cx.tcx;
- if a == b || rustc_middle::ty::TyS::same_type(a, b) {
- // All nominally-same types are structurally same, too.
- true
- } else {
- // Do a full, depth-first comparison between the two.
- use rustc_middle::ty::TyKind::*;
- let a_kind = &a.kind;
- let b_kind = &b.kind;
-
- let compare_layouts = |a, b| -> bool {
- let a_layout = &cx.layout_of(a).unwrap().layout.abi;
- let b_layout = &cx.layout_of(b).unwrap().layout.abi;
- debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout);
- a_layout == b_layout
- };
+ fn structurally_same_type_impl<'tcx>(
+ seen_types: &mut FxHashSet<(Ty<'tcx>, Ty<'tcx>)>,
+ cx: &LateContext<'tcx>,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>,
+ ckind: CItemKind,
+ ) -> bool {
+ debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b);
+ if !seen_types.insert((a, b)) {
+ // We've encountered a cycle. There's no point going any further -- the types are
+ // structurally the same.
+ return true;
+ }
+ let tcx = cx.tcx;
+ if a == b || rustc_middle::ty::TyS::same_type(a, b) {
+ // All nominally-same types are structurally same, too.
+ true
+ } else {
+ // Do a full, depth-first comparison between the two.
+ use rustc_middle::ty::TyKind::*;
+ let a_kind = &a.kind;
+ let b_kind = &b.kind;
+
+ let compare_layouts = |a, b| -> bool {
+ let a_layout = &cx.layout_of(a).unwrap().layout.abi;
+ let b_layout = &cx.layout_of(b).unwrap().layout.abi;
+ debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout);
+ a_layout == b_layout
+ };
+
+ #[allow(rustc::usage_of_ty_tykind)]
+ let is_primitive_or_pointer = |kind: &ty::TyKind<'_>| {
+ kind.is_primitive() || matches!(kind, RawPtr(..) | Ref(..))
+ };
- #[allow(rustc::usage_of_ty_tykind)]
- let is_primitive_or_pointer =
- |kind: &ty::TyKind<'_>| kind.is_primitive() || matches!(kind, RawPtr(..));
-
- match (a_kind, b_kind) {
- (Adt(_, a_substs), Adt(_, b_substs)) => {
- let a = a.subst(cx.tcx, a_substs);
- let b = b.subst(cx.tcx, b_substs);
- debug!("Comparing {:?} and {:?}", a, b);
-
- if let (Adt(a_def, ..), Adt(b_def, ..)) = (&a.kind, &b.kind) {
- // Grab a flattened representation of all fields.
- let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
- let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
- compare_layouts(a, b)
+ ensure_sufficient_stack(|| {
+ match (a_kind, b_kind) {
+ (Adt(a_def, a_substs), Adt(b_def, b_substs)) => {
+ let a = a.subst(cx.tcx, a_substs);
+ let b = b.subst(cx.tcx, b_substs);
+ debug!("Comparing {:?} and {:?}", a, b);
+
+ // Grab a flattened representation of all fields.
+ let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter());
+ let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter());
+ compare_layouts(a, b)
&& a_fields.eq_by(
b_fields,
|&ty::FieldDef { did: a_did, .. },
&ty::FieldDef { did: b_did, .. }| {
- Self::structurally_same_type(
+ structurally_same_type_impl(
+ seen_types,
cx,
tcx.type_of(a_did),
tcx.type_of(b_did),
)
},
)
- } else {
- unreachable!()
- }
- }
- (Array(a_ty, a_const), Array(b_ty, b_const)) => {
- // For arrays, we also check the constness of the type.
- a_const.val == b_const.val
- && Self::structurally_same_type(cx, a_const.ty, b_const.ty, ckind)
- && Self::structurally_same_type(cx, a_ty, b_ty, ckind)
- }
- (Slice(a_ty), Slice(b_ty)) => Self::structurally_same_type(cx, a_ty, b_ty, ckind),
- (RawPtr(a_tymut), RawPtr(b_tymut)) => {
- a_tymut.mutbl == b_tymut.mutbl
- && Self::structurally_same_type(cx, &a_tymut.ty, &b_tymut.ty, ckind)
- }
- (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
- // For structural sameness, we don't need the region to be same.
- a_mut == b_mut && Self::structurally_same_type(cx, a_ty, b_ty, ckind)
- }
- (FnDef(..), FnDef(..)) => {
- 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();
-
- (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
- == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
- && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
- Self::structurally_same_type(cx, a, b, ckind)
- })
- && Self::structurally_same_type(cx, a_sig.output(), b_sig.output(), ckind)
- }
- (Tuple(a_substs), Tuple(b_substs)) => {
- a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| {
- Self::structurally_same_type(cx, a_ty, b_ty, ckind)
- })
- }
- // For these, it's not quite as easy to define structural-sameness quite so easily.
- // For the purposes of this lint, take the conservative approach and mark them as
- // not structurally same.
- (Dynamic(..), Dynamic(..))
- | (Error(..), Error(..))
- | (Closure(..), Closure(..))
- | (Generator(..), Generator(..))
- | (GeneratorWitness(..), GeneratorWitness(..))
- | (Projection(..), Projection(..))
- | (Opaque(..), Opaque(..)) => false,
-
- // These definitely should have been caught above.
- (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
-
- // An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a
- // non-null field.
- (Adt(..), other_kind) | (other_kind, Adt(..))
- if is_primitive_or_pointer(other_kind) =>
- {
- let (primitive, adt) =
- if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) };
- if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
- ty == primitive
- } else {
- compare_layouts(a, b)
+ }
+ (Array(a_ty, a_const), Array(b_ty, b_const)) => {
+ // For arrays, we also check the constness of the type.
+ a_const.val == b_const.val
+ && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+ }
+ (Slice(a_ty), Slice(b_ty)) => {
+ structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+ }
+ (RawPtr(a_tymut), RawPtr(b_tymut)) => {
+ a_tymut.mutbl == b_tymut.mutbl
+ && structurally_same_type_impl(
+ seen_types,
+ cx,
+ &a_tymut.ty,
+ &b_tymut.ty,
+ ckind,
+ )
+ }
+ (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
+ // For structural sameness, we don't need the region to be same.
+ a_mut == b_mut
+ && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+ }
+ (FnDef(..), FnDef(..)) => {
+ 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();
+
+ (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
+ == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
+ && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
+ structurally_same_type_impl(seen_types, cx, a, b, ckind)
+ })
+ && structurally_same_type_impl(
+ seen_types,
+ cx,
+ a_sig.output(),
+ b_sig.output(),
+ ckind,
+ )
+ }
+ (Tuple(a_substs), Tuple(b_substs)) => {
+ a_substs.types().eq_by(b_substs.types(), |a_ty, b_ty| {
+ structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+ })
+ }
+ // For these, it's not quite as easy to define structural-sameness quite so easily.
+ // For the purposes of this lint, take the conservative approach and mark them as
+ // not structurally same.
+ (Dynamic(..), Dynamic(..))
+ | (Error(..), Error(..))
+ | (Closure(..), Closure(..))
+ | (Generator(..), Generator(..))
+ | (GeneratorWitness(..), GeneratorWitness(..))
+ | (Projection(..), Projection(..))
+ | (Opaque(..), Opaque(..)) => false,
+
+ // These definitely should have been caught above.
+ (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(),
+
+ // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
+ // enum layout optimisation is being applied.
+ (Adt(..), other_kind) | (other_kind, Adt(..))
+ if is_primitive_or_pointer(other_kind) =>
+ {
+ let (primitive, adt) =
+ if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) };
+ if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) {
+ ty == primitive
+ } else {
+ compare_layouts(a, b)
+ }
+ }
+ // Otherwise, just compare the layouts. This may fail to lint for some
+ // incompatible types, but at the very least, will stop reads into
+ // uninitialised memory.
+ _ => compare_layouts(a, b),
}
- }
- // Otherwise, just compare the layouts. This may fail to lint for some
- // incompatible types, but at the very least, will stop reads into
- // uninitialised memory.
- _ => compare_layouts(a, b),
+ })
}
}
+ let mut seen_types = FxHashSet::default();
+ structurally_same_type_impl(&mut seen_types, cx, a, b, ckind)
}
}
}
fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
- match (self.expr_is_complete(lhs), self.check_assoc_op().map(|op| op.node)) {
+ match (self.expr_is_complete(lhs), AssocOp::from_token(&self.token)) {
// Semi-statement forms are odd:
// See https://github.com/rust-lang/rust/issues/29071
(true, None) => false,
match *clean_type {
clean::ResolvedPath { ref path, .. } => {
let segments = &path.segments;
- let path_segment = segments.iter().last().unwrap_or_else(|| panic!(
+ let path_segment = segments.iter().last().unwrap_or_else(|| {
+ panic!(
"get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path",
clean_type, accept_generic
- ));
+ )
+ });
Some(path_segment.name.clone())
}
clean::Generic(ref s) if accept_generic => Some(s.clone()),
use crate::config::OutputFormat;
use crate::core::DocContext;
use crate::fold::{self, DocFolder};
+use crate::html::markdown::{find_testable_code, ErrorCodes};
+use crate::passes::doc_test_lints::Tests;
use crate::passes::Pass;
-
use rustc_span::symbol::sym;
use rustc_span::FileName;
use serde::Serialize;
struct ItemCount {
total: u64,
with_docs: u64,
+ with_examples: u64,
}
impl ItemCount {
- fn count_item(&mut self, has_docs: bool) {
+ fn count_item(&mut self, has_docs: bool, has_doc_example: bool) {
self.total += 1;
if has_docs {
self.with_docs += 1;
}
+ if has_doc_example {
+ self.with_examples += 1;
+ }
}
fn percentage(&self) -> Option<f64> {
None
}
}
+
+ fn examples_percentage(&self) -> Option<f64> {
+ if self.total > 0 {
+ Some((self.with_examples as f64 * 100.0) / self.total as f64)
+ } else {
+ None
+ }
+ }
}
impl ops::Sub for ItemCount {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
- ItemCount { total: self.total - rhs.total, with_docs: self.with_docs - rhs.with_docs }
+ ItemCount {
+ total: self.total - rhs.total,
+ with_docs: self.with_docs - rhs.with_docs,
+ with_examples: self.with_examples - rhs.with_examples,
+ }
}
}
fn add_assign(&mut self, rhs: Self) {
self.total += rhs.total;
self.with_docs += rhs.with_docs;
+ self.with_examples += rhs.with_examples;
}
}
let mut total = ItemCount::default();
fn print_table_line() {
- println!("+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", "");
+ println!("+-{0:->35}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+-{0:->10}-+", "");
}
- fn print_table_record(name: &str, count: ItemCount, percentage: f64) {
+ fn print_table_record(
+ name: &str,
+ count: ItemCount,
+ percentage: f64,
+ examples_percentage: f64,
+ ) {
println!(
- "| {:<35} | {:>10} | {:>10} | {:>9.1}% |",
- name, count.with_docs, count.total, percentage
+ "| {:<35} | {:>10} | {:>10} | {:>9.1}% | {:>10} | {:>9.1}% |",
+ name,
+ count.with_docs,
+ count.total,
+ percentage,
+ count.with_examples,
+ examples_percentage,
);
}
print_table_line();
println!(
- "| {:<35} | {:>10} | {:>10} | {:>10} |",
- "File", "Documented", "Total", "Percentage"
+ "| {:<35} | {:>10} | {:>10} | {:>10} | {:>10} | {:>10} |",
+ "File", "Documented", "Total", "Percentage", "Examples", "Percentage",
);
print_table_line();
for (file, &count) in &self.items {
- if let Some(percentage) = count.percentage() {
- print_table_record(&limit_filename_len(file.to_string()), count, percentage);
+ if let (Some(percentage), Some(examples_percentage)) =
+ (count.percentage(), count.examples_percentage())
+ {
+ print_table_record(
+ &limit_filename_len(file.to_string()),
+ count,
+ percentage,
+ examples_percentage,
+ );
total += count;
}
}
print_table_line();
- print_table_record("Total", total, total.percentage().unwrap_or(0.0));
+ print_table_record(
+ "Total",
+ total,
+ total.percentage().unwrap_or(0.0),
+ total.examples_percentage().unwrap_or(0.0),
+ );
print_table_line();
}
}
impl fold::DocFolder for CoverageCalculator {
fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
let has_docs = !i.attrs.doc_strings.is_empty();
+ let mut tests = Tests { found_tests: 0 };
+
+ find_testable_code(
+ &i.attrs.doc_strings.iter().map(|d| d.as_str()).collect::<Vec<_>>().join("\n"),
+ &mut tests,
+ ErrorCodes::No,
+ false,
+ None,
+ );
+
+ let has_doc_example = tests.found_tests != 0;
match i.inner {
_ if !i.def_id.is_local() => {
}
_ => {
debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename);
- self.items.entry(i.source.filename.clone()).or_default().count_item(has_docs);
+ self.items
+ .entry(i.source.filename.clone())
+ .or_default()
+ .count_item(has_docs, has_doc_example);
}
}
disambiguator,
None | Some(Disambiguator::Namespace(Namespace::TypeNS))
) {
- if let Some(prim) = is_primitive(path_str, ns) {
+ if let Some((path, prim)) = is_primitive(path_str, ns) {
if extra_fragment.is_some() {
return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
}
- return Ok((prim, Some(path_str.to_owned())));
+ return Ok((prim, Some(path.to_owned())));
}
}
return Ok((res, extra_fragment.clone()));
if value != (ns == ValueNS) {
return Err(ErrorKind::ResolutionFailure);
}
- } else if let Some(prim) = is_primitive(path_str, ns) {
+ } else if let Some((path, prim)) = is_primitive(path_str, ns) {
if extra_fragment.is_some() {
return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
}
- return Ok((prim, Some(path_str.to_owned())));
+ return Ok((prim, Some(path.to_owned())));
} else {
// If resolution failed, it may still be a method
// because methods are not handled by the resolver
})
.ok_or(ErrorKind::ResolutionFailure)?;
- if let Some(prim) = is_primitive(&path, TypeNS) {
+ if let Some((path, prim)) = is_primitive(&path, TypeNS) {
let did = primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)?;
return cx
.tcx
("f64", Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F64))),
("str", Res::PrimTy(hir::PrimTy::Str)),
("bool", Res::PrimTy(hir::PrimTy::Bool)),
+ ("true", Res::PrimTy(hir::PrimTy::Bool)),
+ ("false", Res::PrimTy(hir::PrimTy::Bool)),
("char", Res::PrimTy(hir::PrimTy::Char)),
];
-fn is_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
- if ns == TypeNS { PRIMITIVES.iter().find(|x| x.0 == path_str).map(|x| x.1) } else { None }
+fn is_primitive(path_str: &str, ns: Namespace) -> Option<(&'static str, Res)> {
+ if ns == TypeNS {
+ PRIMITIVES
+ .iter()
+ .filter(|x| x.0 == path_str)
+ .copied()
+ .map(|x| if x.0 == "true" || x.0 == "false" { ("bool", x.1) } else { x })
+ .next()
+ } else {
+ None
+ }
}
fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<DefId> {
}
}
+pub(crate) struct Tests {
+ pub(crate) found_tests: usize,
+}
+
+impl Tests {
+ pub(crate) fn new() -> Tests {
+ Tests { found_tests: 0 }
+ }
+}
+
+impl crate::test::Tester for Tests {
+ fn add_test(&mut self, _: String, _: LangString, _: usize) {
+ self.found_tests += 1;
+ }
+}
+
pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
let hir_id = match cx.as_local_hir_id(item.def_id) {
Some(hir_id) => hir_id,
}
};
- struct Tests {
- found_tests: usize,
- }
-
- impl crate::test::Tester for Tests {
- fn add_test(&mut self, _: String, _: LangString, _: usize) {
- self.found_tests += 1;
- }
- }
-
- let mut tests = Tests { found_tests: 0 };
+ let mut tests = Tests::new();
find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
-+-------------------------------------+------------+------------+------------+
-| File | Documented | Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...est/rustdoc-ui/coverage/basic.rs | 7 | 14 | 50.0% |
-+-------------------------------------+------------+------------+------------+
-| Total | 7 | 14 | 50.0% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File | Documented | Total | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...est/rustdoc-ui/coverage/basic.rs | 7 | 14 | 50.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total | 7 | 14 | 50.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
--- /dev/null
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+//! This test ensure that only rust code examples are counted.
+
+/// Doc
+///
+/// ```
+/// let x = 2;
+/// ```
+pub struct Foo;
+
+/// Doc
+///
+/// ```text
+/// yolo
+/// ```
+pub trait Bar {}
+
+/// Doc
+///
+/// ```ignore (just for the sake of this test)
+/// let x = 2;
+/// ```
+pub fn foo<T: Bar, D: ::std::fmt::Debug>(a: Foo, b: u32, c: T, d: D) -> u32 {
+ 0
+}
--- /dev/null
++-------------------------------------+------------+------------+------------+------------+------------+
+| File | Documented | Total | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...tdoc-ui/coverage/doc-examples.rs | 4 | 4 | 100.0% | 2 | 50.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total | 4 | 4 | 100.0% | 2 | 50.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
-+-------------------------------------+------------+------------+------------+
-| File | Documented | Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...est/rustdoc-ui/coverage/empty.rs | 0 | 1 | 0.0% |
-+-------------------------------------+------------+------------+------------+
-| Total | 0 | 1 | 0.0% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File | Documented | Total | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...est/rustdoc-ui/coverage/empty.rs | 0 | 1 | 0.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total | 0 | 1 | 0.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
-+-------------------------------------+------------+------------+------------+
-| File | Documented | Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...est/rustdoc-ui/coverage/enums.rs | 6 | 8 | 75.0% |
-+-------------------------------------+------------+------------+------------+
-| Total | 6 | 8 | 75.0% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File | Documented | Total | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...est/rustdoc-ui/coverage/enums.rs | 6 | 8 | 75.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total | 6 | 8 | 75.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
-+-------------------------------------+------------+------------+------------+
-| File | Documented | Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...st/rustdoc-ui/coverage/exotic.rs | 1 | 1 | 100.0% |
-| <anon> | 2 | 2 | 100.0% |
-+-------------------------------------+------------+------------+------------+
-| Total | 3 | 3 | 100.0% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File | Documented | Total | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...st/rustdoc-ui/coverage/exotic.rs | 1 | 1 | 100.0% | 0 | 0.0% |
+| <anon> | 2 | 2 | 100.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total | 3 | 3 | 100.0% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
-{"$DIR/json.rs":{"total":13,"with_docs":7}}
+{"$DIR/json.rs":{"total":13,"with_docs":7,"with_examples":0}}
-+-------------------------------------+------------+------------+------------+
-| File | Documented | Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...t/rustdoc-ui/coverage/private.rs | 4 | 7 | 57.1% |
-+-------------------------------------+------------+------------+------------+
-| Total | 4 | 7 | 57.1% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File | Documented | Total | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...t/rustdoc-ui/coverage/private.rs | 4 | 7 | 57.1% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total | 4 | 7 | 57.1% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
-+-------------------------------------+------------+------------+------------+
-| File | Documented | Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...oc-ui/coverage/statics-consts.rs | 6 | 7 | 85.7% |
-+-------------------------------------+------------+------------+------------+
-| Total | 6 | 7 | 85.7% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File | Documented | Total | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...oc-ui/coverage/statics-consts.rs | 6 | 7 | 85.7% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total | 6 | 7 | 85.7% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
-+-------------------------------------+------------+------------+------------+
-| File | Documented | Total | Percentage |
-+-------------------------------------+------------+------------+------------+
-| ...st/rustdoc-ui/coverage/traits.rs | 6 | 7 | 85.7% |
-+-------------------------------------+------------+------------+------------+
-| Total | 6 | 7 | 85.7% |
-+-------------------------------------+------------+------------+------------+
++-------------------------------------+------------+------------+------------+------------+------------+
+| File | Documented | Total | Percentage | Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+------------+
+| ...st/rustdoc-ui/coverage/traits.rs | 6 | 7 | 85.7% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
+| Total | 6 | 7 | 85.7% | 0 | 0.0% |
++-------------------------------------+------------+------------+------------+------------+------------+
--- /dev/null
+#![deny(broken_intra_doc_links)]
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+// @has foo/index.html
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'true'
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'false'
+
+//! A `bool` is either [`true`] or [`false`].
let b = false;
let _ = a and b; //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
if a and b { //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
println!("both");
}
let b = false;
let _ = a or b; //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
if a or b { //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
if (a and b) { //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
if (a or b) { //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
while a and b { //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
while a or b { //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
println!("both");
}
}
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
error: `and` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:7:15
- |
-LL | let _ = a and b;
- | ^^^ help: use `&&` to perform logical conjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `and` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:10:10
- |
-LL | if a and b {
- | ^^^ help: use `&&` to perform logical conjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `and` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:10:10
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:9:10
|
LL | if a and b {
| ^^^ help: use `&&` to perform logical conjunction
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
error: `or` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:15
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:20:15
|
LL | let _ = a or b;
| ^^ help: use `||` to perform logical disjunction
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
error: `or` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:15
- |
-LL | let _ = a or b;
- | ^^ help: use `||` to perform logical disjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:25:10
- |
-LL | if a or b {
- | ^^ help: use `||` to perform logical disjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:25:10
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:22:10
|
LL | if a or b {
| ^^ help: use `||` to perform logical disjunction
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
error: `and` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:34:11
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:30:11
|
LL | if (a and b) {
| ^^^ help: use `&&` to perform logical conjunction
|
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-error: `and` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:34:11
- |
-LL | if (a and b) {
- | ^^^ help: use `&&` to perform logical conjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:43:11
- |
-LL | if (a or b) {
- | ^^ help: use `||` to perform logical disjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
error: `or` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:43:11
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:38:11
|
LL | if (a or b) {
| ^^ help: use `||` to perform logical disjunction
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
error: `and` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:52:13
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:46:13
|
LL | while a and b {
| ^^^ help: use `&&` to perform logical conjunction
|
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-error: `and` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:52:13
- |
-LL | while a and b {
- | ^^^ help: use `&&` to perform logical conjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:61:13
- |
-LL | while a or b {
- | ^^ help: use `||` to perform logical disjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
error: `or` is not a logical operator
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:61:13
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:54:13
|
LL | while a or b {
| ^^ help: use `||` to perform logical disjunction
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
error[E0308]: mismatched types
- --> $DIR/issue-54109-and_instead_of_ampersands.rs:15:33
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:13:33
|
LL | let _recovery_witness: () = 0;
| -- ^ expected `()`, found integer
| |
| expected due to this
-error: aborting due to 17 previous errors
+error: aborting due to 9 previous errors
For more information about this error, try `rustc --explain E0308`.
let b = false;
let _ = a && b; //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
if a && b { //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
println!("both");
}
}
let b = false;
let _ = a || b; //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
if a || b { //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
if (a && b) { //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
if (a || b) { //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
while a && b { //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
while a || b { //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
println!("both");
}
}
let b = false;
let _ = a and b; //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
if a and b { //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
println!("both");
}
}
let b = false;
let _ = a or b; //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
if a or b { //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
if (a and b) { //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
if (a or b) { //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
while a and b { //~ ERROR `and` is not a logical operator
- //~| ERROR `and` is not a logical operator
println!("both");
}
}
let a = true;
let b = false;
while a or b { //~ ERROR `or` is not a logical operator
- //~| ERROR `or` is not a logical operator
println!("both");
}
}
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
error: `and` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:13:15
- |
-LL | let _ = a and b;
- | ^^^ help: use `&&` to perform logical conjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `and` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:16:10
- |
-LL | if a and b {
- | ^^^ help: use `&&` to perform logical conjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `and` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:16:10
+ --> $DIR/issue-54109-without-witness.rs:15:10
|
LL | if a and b {
| ^^^ help: use `&&` to perform logical conjunction
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
error: `or` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:26:15
+ --> $DIR/issue-54109-without-witness.rs:24:15
|
LL | let _ = a or b;
| ^^ help: use `||` to perform logical disjunction
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
error: `or` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:26:15
- |
-LL | let _ = a or b;
- | ^^ help: use `||` to perform logical disjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:29:10
- |
-LL | if a or b {
- | ^^ help: use `||` to perform logical disjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:29:10
+ --> $DIR/issue-54109-without-witness.rs:26:10
|
LL | if a or b {
| ^^ help: use `||` to perform logical disjunction
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
error: `and` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:38:11
+ --> $DIR/issue-54109-without-witness.rs:34:11
|
LL | if (a and b) {
| ^^^ help: use `&&` to perform logical conjunction
|
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-error: `and` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:38:11
- |
-LL | if (a and b) {
- | ^^^ help: use `&&` to perform logical conjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:47:11
- |
-LL | if (a or b) {
- | ^^ help: use `||` to perform logical disjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
error: `or` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:47:11
+ --> $DIR/issue-54109-without-witness.rs:42:11
|
LL | if (a or b) {
| ^^ help: use `||` to perform logical disjunction
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
error: `and` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:56:13
+ --> $DIR/issue-54109-without-witness.rs:50:13
|
LL | while a and b {
| ^^^ help: use `&&` to perform logical conjunction
|
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-error: `and` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:56:13
- |
-LL | while a and b {
- | ^^^ help: use `&&` to perform logical conjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
-error: `or` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:65:13
- |
-LL | while a or b {
- | ^^ help: use `||` to perform logical disjunction
- |
- = note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-
error: `or` is not a logical operator
- --> $DIR/issue-54109-without-witness.rs:65:13
+ --> $DIR/issue-54109-without-witness.rs:58:13
|
LL | while a or b {
| ^^ help: use `||` to perform logical disjunction
|
= note: unlike in e.g., python and PHP, `&&` and `||` are used for logical operators
-error: aborting due to 16 previous errors
+error: aborting due to 8 previous errors
--- /dev/null
+// check-pass
+#![allow(non_upper_case_globals)]
+
+const or: usize = 1;
+const and: usize = 2;
+
+mod or {
+ pub const X: usize = 3;
+}
+
+mod and {
+ pub const X: usize = 4;
+}
+
+fn main() {
+ match 0 {
+ 0 => {}
+ or => {}
+ and => {}
+ or::X => {}
+ and::X => {}
+ _ => {}
+ }
+}
--- /dev/null
+// check-pass
+//
+// This tests checks that clashing_extern_declarations handles types that are recursive through a
+// pointer or ref argument. See #75512.
+
+#![crate_type = "lib"]
+
+mod raw_ptr_recursion {
+ mod a {
+ #[repr(C)]
+ struct Pointy {
+ pointy: *const Pointy,
+ }
+
+ extern "C" {
+ fn run_pointy(pointy: Pointy);
+ }
+ }
+ mod b {
+ #[repr(C)]
+ struct Pointy {
+ pointy: *const Pointy,
+ }
+
+ extern "C" {
+ fn run_pointy(pointy: Pointy);
+ }
+ }
+}
+
+mod raw_ptr_recursion_once_removed {
+ mod a {
+ #[repr(C)]
+ struct Pointy1 {
+ pointy_two: *const Pointy2,
+ }
+
+ #[repr(C)]
+ struct Pointy2 {
+ pointy_one: *const Pointy1,
+ }
+
+ extern "C" {
+ fn run_pointy2(pointy: Pointy2);
+ }
+ }
+
+ mod b {
+ #[repr(C)]
+ struct Pointy1 {
+ pointy_two: *const Pointy2,
+ }
+
+ #[repr(C)]
+ struct Pointy2 {
+ pointy_one: *const Pointy1,
+ }
+
+ extern "C" {
+ fn run_pointy2(pointy: Pointy2);
+ }
+ }
+}
+
+mod ref_recursion {
+ mod a {
+ #[repr(C)]
+ struct Reffy<'a> {
+ reffy: &'a Reffy<'a>,
+ }
+
+ extern "C" {
+ fn reffy_recursion(reffy: Reffy);
+ }
+ }
+ mod b {
+ #[repr(C)]
+ struct Reffy<'a> {
+ reffy: &'a Reffy<'a>,
+ }
+
+ extern "C" {
+ fn reffy_recursion(reffy: Reffy);
+ }
+ }
+}
+
+mod ref_recursion_once_removed {
+ mod a {
+ #[repr(C)]
+ struct Reffy1<'a> {
+ reffy: &'a Reffy2<'a>,
+ }
+
+ struct Reffy2<'a> {
+ reffy: &'a Reffy1<'a>,
+ }
+
+ extern "C" {
+ #[allow(improper_ctypes)]
+ fn reffy_once_removed(reffy: Reffy1);
+ }
+ }
+ mod b {
+ #[repr(C)]
+ struct Reffy1<'a> {
+ reffy: &'a Reffy2<'a>,
+ }
+
+ struct Reffy2<'a> {
+ reffy: &'a Reffy1<'a>,
+ }
+
+ extern "C" {
+ #[allow(improper_ctypes)]
+ fn reffy_once_removed(reffy: Reffy1);
+ }
+ }
+}