Auto merge of #75244 - Manishearth:rollup-dzfyjva, r=Manishearth

Rollup of 4 pull requests

Successful merges:

 - #74774 (adds [*mut|*const] ptr::set_ptr_value)
 - #75079 (Disallow linking to items with a mismatched disambiguator)
 - #75203 (Make `IntoIterator` lifetime bounds of `&BTreeMap` match with `&HashMap` )
 - #75227 (Fix ICE when using asm! on an unsupported architecture)

Failed merges:

r? @ghost
This commit is contained in:
bors 2020-08-07 06:40:53 +00:00
commit d4c940f082
15 changed files with 447 additions and 54 deletions

View file

@ -1294,7 +1294,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap<K, V> {
impl<'a, K, V> IntoIterator for &'a BTreeMap<K, V> {
type Item = (&'a K, &'a V);
type IntoIter = Iter<'a, K, V>;
@ -1363,7 +1363,7 @@ impl<K, V> Clone for Iter<'_, K, V> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap<K, V> {
impl<'a, K, V> IntoIterator for &'a mut BTreeMap<K, V> {
type Item = (&'a K, &'a mut V);
type IntoIter = IterMut<'a, K, V>;

View file

@ -656,6 +656,38 @@ impl<T: ?Sized> *const T {
self.wrapping_offset((count as isize).wrapping_neg())
}
/// Sets the pointer value to `ptr`.
///
/// In case `self` is a (fat) pointer to an unsized type, this operation
/// will only affect the pointer part, whereas for (thin) pointers to
/// sized types, this has the same effect as a simple assignment.
///
/// # Examples
///
/// This function is primarily useful for allowing byte-wise pointer
/// arithmetic on potentially fat pointers:
///
/// ```
/// #![feature(set_ptr_value)]
/// # use core::fmt::Debug;
/// let arr: [i32; 3] = [1, 2, 3];
/// let mut ptr = &arr[0] as *const dyn Debug;
/// let thin = ptr as *const u8;
/// ptr = ptr.set_ptr_value(unsafe { thin.add(8).cast() });
/// assert_eq!(unsafe { *(ptr as *const i32) }, 3);
/// ```
#[unstable(feature = "set_ptr_value", issue = "75091")]
#[inline]
pub fn set_ptr_value(mut self, val: *const ()) -> Self {
let thin = &mut self as *mut *const T as *mut *const ();
// SAFETY: In case of a thin pointer, this operations is identical
// to a simple assignment. In case of a fat pointer, with the current
// fat pointer layout implementation, the first field of such a
// pointer is always the data pointer, which is likewise assigned.
unsafe { *thin = val };
self
}
/// Reads the value from `self` without moving it. This leaves the
/// memory in `self` unchanged.
///

View file

@ -712,6 +712,38 @@ impl<T: ?Sized> *mut T {
self.wrapping_offset((count as isize).wrapping_neg())
}
/// Sets the pointer value to `ptr`.
///
/// In case `self` is a (fat) pointer to an unsized type, this operation
/// will only affect the pointer part, whereas for (thin) pointers to
/// sized types, this has the same effect as a simple assignment.
///
/// # Examples
///
/// This function is primarily useful for allowing byte-wise pointer
/// arithmetic on potentially fat pointers:
///
/// ```
/// #![feature(set_ptr_value)]
/// # use core::fmt::Debug;
/// let mut arr: [i32; 3] = [1, 2, 3];
/// let mut ptr = &mut arr[0] as *mut dyn Debug;
/// let thin = ptr as *mut u8;
/// ptr = ptr.set_ptr_value(unsafe { thin.add(8).cast() });
/// assert_eq!(unsafe { *(ptr as *mut i32) }, 3);
/// ```
#[unstable(feature = "set_ptr_value", issue = "75091")]
#[inline]
pub fn set_ptr_value(mut self, val: *mut ()) -> Self {
let thin = &mut self as *mut *mut T as *mut *mut ();
// SAFETY: In case of a thin pointer, this operations is identical
// to a simple assignment. In case of a fat pointer, with the current
// fat pointer layout implementation, the first field of such a
// pointer is always the data pointer, which is likewise assigned.
unsafe { *thin = val };
self
}
/// Reads the value from `self` without moving it. This leaves the
/// memory in `self` unchanged.
///

View file

@ -1067,7 +1067,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
.collect();
// Stop if there were any errors when lowering the register classes
if operands.len() != asm.operands.len() {
if operands.len() != asm.operands.len() || sess.asm_arch.is_none() {
return hir::ExprKind::Err;
}

View file

@ -150,7 +150,7 @@ impl DefKind {
}
}
pub fn matches_ns(&self, ns: Namespace) -> bool {
pub fn ns(&self) -> Option<Namespace> {
match self {
DefKind::Mod
| DefKind::Struct
@ -163,7 +163,7 @@ impl DefKind {
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
| DefKind::TyParam => ns == Namespace::TypeNS,
| DefKind::TyParam => Some(Namespace::TypeNS),
DefKind::Fn
| DefKind::Const
@ -171,9 +171,9 @@ impl DefKind {
| DefKind::Static
| DefKind::Ctor(..)
| DefKind::AssocFn
| DefKind::AssocConst => ns == Namespace::ValueNS,
| DefKind::AssocConst => Some(Namespace::ValueNS),
DefKind::Macro(..) => ns == Namespace::MacroNS,
DefKind::Macro(..) => Some(Namespace::MacroNS),
// Not namespaced.
DefKind::AnonConst
@ -185,7 +185,7 @@ impl DefKind {
| DefKind::Use
| DefKind::ForeignMod
| DefKind::GlobalAsm
| DefKind::Impl => false,
| DefKind::Impl => None,
}
}
}
@ -453,7 +453,7 @@ impl<Id> Res<Id> {
pub fn matches_ns(&self, ns: Namespace) -> bool {
match self {
Res::Def(kind, ..) => kind.matches_ns(ns),
Res::Def(kind, ..) => kind.ns() == Some(ns),
Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => ns == Namespace::TypeNS,
Res::SelfCtor(..) | Res::Local(..) => ns == Namespace::ValueNS,
Res::NonMacroAttr(..) => ns == Namespace::MacroNS,

View file

@ -607,6 +607,9 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId {
Res::Def(DefKind::TyAlias, i) => (i, TypeKind::Typedef),
Res::Def(DefKind::Enum, i) => (i, TypeKind::Enum),
Res::Def(DefKind::Trait, i) => (i, TypeKind::Trait),
Res::Def(DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst, i) => {
(cx.tcx.parent(i).unwrap(), TypeKind::Trait)
}
Res::Def(DefKind::Struct, i) => (i, TypeKind::Struct),
Res::Def(DefKind::Union, i) => (i, TypeKind::Union),
Res::Def(DefKind::Mod, i) => (i, TypeKind::Module),

View file

@ -17,6 +17,7 @@ use rustc_span::symbol::Ident;
use rustc_span::symbol::Symbol;
use rustc_span::DUMMY_SP;
use std::cell::Cell;
use std::ops::Range;
use crate::clean::*;
@ -62,11 +63,15 @@ struct LinkCollector<'a, 'tcx> {
cx: &'a DocContext<'tcx>,
// NOTE: this may not necessarily be a module in the current crate
mod_ids: Vec<DefId>,
/// This is used to store the kind of associated items,
/// because `clean` and the disambiguator code expect them to be different.
/// See the code for associated items on inherent impls for details.
kind_side_channel: Cell<Option<DefKind>>,
}
impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
fn new(cx: &'a DocContext<'tcx>) -> Self {
LinkCollector { cx, mod_ids: Vec::new() }
LinkCollector { cx, mod_ids: Vec::new(), kind_side_channel: Cell::new(None) }
}
fn variant_field(
@ -174,7 +179,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
fn resolve(
&self,
path_str: &str,
disambiguator: Option<&str>,
disambiguator: Option<Disambiguator>,
ns: Namespace,
current_item: &Option<String>,
parent_id: Option<DefId>,
@ -214,7 +219,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
Res::Def(DefKind::Mod, _) => {
// This resolved to a module, but if we were passed `type@`,
// we want primitive types to take precedence instead.
if disambiguator == Some("type") {
if disambiguator == Some(Disambiguator::Namespace(Namespace::TypeNS)) {
if let Some(prim) = is_primitive(path_str, ns) {
if extra_fragment.is_some() {
return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
@ -347,6 +352,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
AnchorFailure::AssocConstant
}))
} else {
// HACK(jynelson): `clean` expects the type, not the associated item.
// but the disambiguator logic expects the associated item.
// Store the kind in a side channel so that only the disambiguator logic looks at it.
self.kind_side_channel.replace(Some(item.kind.as_def_kind()));
Ok((ty_res, Some(format!("{}.{}", out, item_name))))
}
} else {
@ -415,7 +424,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
AnchorFailure::Method
}))
} else {
Ok((ty_res, Some(format!("{}.{}", kind, item_name))))
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
Ok((res, Some(format!("{}.{}", kind, item_name))))
}
} else {
self.variant_field(path_str, current_item, module_id)
@ -574,46 +584,14 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
};
let resolved_self;
let mut path_str;
let disambiguator;
let (res, fragment) = {
let mut kind = None;
let mut disambiguator = None;
path_str = if let Some(prefix) =
["struct@", "enum@", "type@", "trait@", "union@", "module@", "mod@"]
.iter()
.find(|p| link.starts_with(**p))
{
kind = Some(TypeNS);
disambiguator = Some(&prefix[..prefix.len() - 1]);
link.trim_start_matches(prefix)
} else if let Some(prefix) =
["const@", "static@", "value@", "function@", "fn@", "method@"]
.iter()
.find(|p| link.starts_with(**p))
{
kind = Some(ValueNS);
disambiguator = Some(&prefix[..prefix.len() - 1]);
link.trim_start_matches(prefix)
} else if link.ends_with("!()") {
kind = Some(MacroNS);
link.trim_end_matches("!()")
} else if link.ends_with("()") {
kind = Some(ValueNS);
disambiguator = Some("fn");
link.trim_end_matches("()")
} else if link.starts_with("macro@") {
kind = Some(MacroNS);
disambiguator = Some("macro");
link.trim_start_matches("macro@")
} else if link.starts_with("derive@") {
kind = Some(MacroNS);
disambiguator = Some("derive");
link.trim_start_matches("derive@")
} else if link.ends_with('!') {
kind = Some(MacroNS);
disambiguator = Some("macro");
link.trim_end_matches('!')
path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) {
disambiguator = Some(d);
path
} else {
&link[..]
disambiguator = None;
&link
}
.trim();
@ -646,7 +624,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
}
}
match kind {
match disambiguator.map(Disambiguator::ns) {
Some(ns @ ValueNS) => {
match self.resolve(
path_str,
@ -789,6 +767,42 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
} else {
debug!("intra-doc link to {} resolved to {:?}", path_str, res);
// Disallow e.g. linking to enums with `struct@`
if let Res::Def(kind, id) = res {
debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
match (self.kind_side_channel.take().unwrap_or(kind), disambiguator) {
| (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
// NOTE: this allows 'method' to mean both normal functions and associated functions
// This can't cause ambiguity because both are in the same namespace.
| (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
// These are namespaces; allow anything in the namespace to match
| (_, Some(Disambiguator::Namespace(_)))
// If no disambiguator given, allow anything
| (_, None)
// All of these are valid, so do nothing
=> {}
(actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
(_, Some(Disambiguator::Kind(expected))) => {
// The resolved item did not match the disambiguator; give a better error than 'not found'
let msg = format!("incompatible link kind for `{}`", path_str);
report_diagnostic(cx, &msg, &item, &dox, link_range, |diag, sp| {
// HACK(jynelson): by looking at the source I saw the DefId we pass
// for `expected.descr()` doesn't matter, since it's not a crate
let note = format!("this link resolved to {} {}, which is not {} {}", kind.article(), kind.descr(id), expected.article(), expected.descr(id));
let suggestion = Disambiguator::display_for(kind, path_str);
let help_msg = format!("to link to the {}, use its disambiguator", kind.descr(id));
diag.note(&note);
if let Some(sp) = sp {
diag.span_suggestion(sp, &help_msg, suggestion, Applicability::MaybeIncorrect);
} else {
diag.help(&format!("{}: {}", help_msg, suggestion));
}
});
continue;
}
}
}
// item can be non-local e.g. when using #[doc(primitive = "pointer")]
if let Some((src_id, dst_id)) = res
.opt_def_id()
@ -837,6 +851,94 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Disambiguator {
Kind(DefKind),
Namespace(Namespace),
}
impl Disambiguator {
/// (disambiguator, path_str)
fn from_str(link: &str) -> Result<(Self, &str), ()> {
use Disambiguator::{Kind, Namespace as NS};
let find_suffix = || {
let suffixes = [
("!()", DefKind::Macro(MacroKind::Bang)),
("()", DefKind::Fn),
("!", DefKind::Macro(MacroKind::Bang)),
];
for &(suffix, kind) in &suffixes {
if link.ends_with(suffix) {
return Ok((Kind(kind), link.trim_end_matches(suffix)));
}
}
Err(())
};
if let Some(idx) = link.find('@') {
let (prefix, rest) = link.split_at(idx);
let d = match prefix {
"struct" => Kind(DefKind::Struct),
"enum" => Kind(DefKind::Enum),
"trait" => Kind(DefKind::Trait),
"union" => Kind(DefKind::Union),
"module" | "mod" => Kind(DefKind::Mod),
"const" | "constant" => Kind(DefKind::Const),
"static" => Kind(DefKind::Static),
"function" | "fn" | "method" => Kind(DefKind::Fn),
"derive" => Kind(DefKind::Macro(MacroKind::Derive)),
"type" => NS(Namespace::TypeNS),
"value" => NS(Namespace::ValueNS),
"macro" => NS(Namespace::MacroNS),
_ => return find_suffix(),
};
Ok((d, &rest[1..]))
} else {
find_suffix()
}
}
fn display_for(kind: DefKind, path_str: &str) -> String {
if kind == DefKind::Macro(MacroKind::Bang) {
return format!("{}!", path_str);
} else if kind == DefKind::Fn || kind == DefKind::AssocFn {
return format!("{}()", path_str);
}
let prefix = match kind {
DefKind::Struct => "struct",
DefKind::Enum => "enum",
DefKind::Trait => "trait",
DefKind::Union => "union",
DefKind::Mod => "mod",
DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => {
"const"
}
DefKind::Static => "static",
DefKind::Macro(MacroKind::Derive) => "derive",
// Now handle things that don't have a specific disambiguator
_ => match kind
.ns()
.expect("tried to calculate a disambiguator for a def without a namespace?")
{
Namespace::TypeNS => "type",
Namespace::ValueNS => "value",
Namespace::MacroNS => "macro",
},
};
format!("{}@{}", prefix, path_str)
}
fn ns(self) -> Namespace {
match self {
Self::Namespace(n) => n,
Self::Kind(k) => {
k.ns().expect("only DefKinds with a valid namespace can be disambiguators")
}
}
}
}
/// Reports a diagnostic for an intra-doc link.
///
/// If no link range is provided, or the source span of the link cannot be determined, the span of

View file

@ -0,0 +1,68 @@
#![deny(broken_intra_doc_links)]
//~^ NOTE lint level is defined
pub enum S {}
macro_rules! m {
() => {};
}
static s: usize = 0;
const c: usize = 0;
trait T {}
/// Link to [struct@S]
//~^ ERROR incompatible link kind for `S`
//~| NOTE this link resolved
//~| HELP use its disambiguator
/// Link to [mod@S]
//~^ ERROR incompatible link kind for `S`
//~| NOTE this link resolved
//~| HELP use its disambiguator
/// Link to [union@S]
//~^ ERROR incompatible link kind for `S`
//~| NOTE this link resolved
//~| HELP use its disambiguator
/// Link to [trait@S]
//~^ ERROR incompatible link kind for `S`
//~| NOTE this link resolved
//~| HELP use its disambiguator
/// Link to [struct@T]
//~^ ERROR incompatible link kind for `T`
//~| NOTE this link resolved
//~| HELP use its disambiguator
/// Link to [derive@m]
//~^ ERROR incompatible link kind for `m`
//~| NOTE this link resolved
//~| HELP use its disambiguator
/// Link to [const@s]
//~^ ERROR incompatible link kind for `s`
//~| NOTE this link resolved
//~| HELP use its disambiguator
/// Link to [static@c]
//~^ ERROR incompatible link kind for `c`
//~| NOTE this link resolved
//~| HELP use its disambiguator
/// Link to [fn@c]
//~^ ERROR incompatible link kind for `c`
//~| NOTE this link resolved
//~| HELP use its disambiguator
/// Link to [c()]
//~^ ERROR incompatible link kind for `c`
//~| NOTE this link resolved
//~| HELP use its disambiguator
/// Link to [const@f]
//~^ ERROR incompatible link kind for `f`
//~| NOTE this link resolved
//~| HELP use its disambiguator
pub fn f() {}

View file

@ -0,0 +1,95 @@
error: incompatible link kind for `S`
--> $DIR/intra-links-disambiguator-mismatch.rs:14:14
|
LL | /// Link to [struct@S]
| ^^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
|
note: the lint level is defined here
--> $DIR/intra-links-disambiguator-mismatch.rs:1:9
|
LL | #![deny(broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^
= note: this link resolved to an enum, which is not a struct
error: incompatible link kind for `S`
--> $DIR/intra-links-disambiguator-mismatch.rs:19:14
|
LL | /// Link to [mod@S]
| ^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
|
= note: this link resolved to an enum, which is not a module
error: incompatible link kind for `S`
--> $DIR/intra-links-disambiguator-mismatch.rs:24:14
|
LL | /// Link to [union@S]
| ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
|
= note: this link resolved to an enum, which is not a union
error: incompatible link kind for `S`
--> $DIR/intra-links-disambiguator-mismatch.rs:29:14
|
LL | /// Link to [trait@S]
| ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
|
= note: this link resolved to an enum, which is not a trait
error: incompatible link kind for `T`
--> $DIR/intra-links-disambiguator-mismatch.rs:34:14
|
LL | /// Link to [struct@T]
| ^^^^^^^^ help: to link to the trait, use its disambiguator: `trait@T`
|
= note: this link resolved to a trait, which is not a struct
error: incompatible link kind for `m`
--> $DIR/intra-links-disambiguator-mismatch.rs:39:14
|
LL | /// Link to [derive@m]
| ^^^^^^^^ help: to link to the macro, use its disambiguator: `m!`
|
= note: this link resolved to a macro, which is not a derive macro
error: incompatible link kind for `s`
--> $DIR/intra-links-disambiguator-mismatch.rs:44:14
|
LL | /// Link to [const@s]
| ^^^^^^^ help: to link to the static, use its disambiguator: `static@s`
|
= note: this link resolved to a static, which is not a constant
error: incompatible link kind for `c`
--> $DIR/intra-links-disambiguator-mismatch.rs:49:14
|
LL | /// Link to [static@c]
| ^^^^^^^^ help: to link to the constant, use its disambiguator: `const@c`
|
= note: this link resolved to a constant, which is not a static
error: incompatible link kind for `c`
--> $DIR/intra-links-disambiguator-mismatch.rs:54:14
|
LL | /// Link to [fn@c]
| ^^^^ help: to link to the constant, use its disambiguator: `const@c`
|
= note: this link resolved to a constant, which is not a function
error: incompatible link kind for `c`
--> $DIR/intra-links-disambiguator-mismatch.rs:59:14
|
LL | /// Link to [c()]
| ^^^ help: to link to the constant, use its disambiguator: `const@c`
|
= note: this link resolved to a constant, which is not a function
error: incompatible link kind for `f`
--> $DIR/intra-links-disambiguator-mismatch.rs:64:14
|
LL | /// Link to [const@f]
| ^^^^^^^ help: to link to the function, use its disambiguator: `f()`
|
= note: this link resolved to a function, which is not a constant
error: aborting due to 11 previous errors

View file

@ -0,0 +1,12 @@
// ignore-tidy-linelength
#![deny(broken_intra_doc_links)]
/// Link to [S::assoc_fn()]
/// Link to [Default::default()]
// @has intra_link_trait_item/struct.S.html '//*[@href="../intra_link_trait_item/struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
// @has - '//*[@href="https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
pub struct S;
impl S {
pub fn assoc_fn() {}
}

View file

@ -0,0 +1,18 @@
// compile-flags: --target wasm32-unknown-unknown
#![feature(no_core, lang_items, rustc_attrs)]
#![no_core]
#[rustc_builtin_macro]
macro_rules! asm {
() => {};
}
#[lang = "sized"]
trait Sized {}
fn main() {
unsafe {
asm!("");
//~^ ERROR asm! is unsupported on this target
}
}

View file

@ -0,0 +1,8 @@
error[E0472]: asm! is unsupported on this target
--> $DIR/bad-arch.rs:15:9
|
LL | asm!("");
| ^^^^^^^^^
error: aborting due to previous error

View file

@ -0,0 +1,23 @@
// check-pass
use std::collections::{BTreeMap, HashMap};
trait Map
where
for<'a> &'a Self: IntoIterator<Item = (&'a Self::Key, &'a Self::Value)>,
{
type Key;
type Value;
}
impl<K, V> Map for HashMap<K, V> {
type Key = K;
type Value = V;
}
impl<K, V> Map for BTreeMap<K, V> {
type Key = K;
type Value = V;
}
fn main() {}

View file

@ -1,4 +1,4 @@
// ignore-emscripten
// only-x86_64
fn main() {
unsafe {

View file

@ -1,4 +1,4 @@
// ignore-emscripten
// only-x86_64
fn main() {
unsafe {