Auto merge of #79377 - jonas-schievink:rollup-ye81i66, r=jonas-schievink
Rollup of 10 pull requests Successful merges: - #76858 (Add exploit mitigations chapter to the rustc book) - #79310 (Make `fold_item_recur` non-nullable) - #79312 (Get rid of `doctree::Impl`) - #79321 (Accept '!' in intra-doc links) - #79346 (Allow using `-Z fewer-names=no` to retain value names) - #79351 (Fix typo in `keyword` docs for traits) - #79354 (BTreeMap: cut out the ceremony around BoxedNode) - #79358 (BTreeMap/BTreeSet: make public doc more consistent) - #79367 (Allow disabling TrapUnreachable via -Ztrap-unreachable=no) - #79374 (Add note to use nightly when using expr in const generics) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
53d19b37c5
92 changed files with 1002 additions and 315 deletions
|
|
@ -152,7 +152,8 @@ pub fn target_machine_factory(
|
|||
let features = features.join(",");
|
||||
let features = CString::new(features).unwrap();
|
||||
let abi = SmallCStr::new(&sess.target.llvm_abiname);
|
||||
let trap_unreachable = sess.target.trap_unreachable;
|
||||
let trap_unreachable =
|
||||
sess.opts.debugging_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable);
|
||||
let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
|
||||
|
||||
let asm_comments = sess.asm_comments();
|
||||
|
|
|
|||
|
|
@ -547,7 +547,7 @@ fn test_debugging_options_tracking_hash() {
|
|||
tracked!(debug_macros, true);
|
||||
tracked!(dep_info_omit_d_target, true);
|
||||
tracked!(dual_proc_macros, true);
|
||||
tracked!(fewer_names, true);
|
||||
tracked!(fewer_names, Some(true));
|
||||
tracked!(force_overflow_checks, Some(true));
|
||||
tracked!(force_unstable_if_unmarked, true);
|
||||
tracked!(fuel, Some(("abc".to_string(), 99)));
|
||||
|
|
@ -592,6 +592,7 @@ fn test_debugging_options_tracking_hash() {
|
|||
tracked!(thinlto, Some(true));
|
||||
tracked!(tune_cpu, Some(String::from("abc")));
|
||||
tracked!(tls_model, Some(TlsModel::GeneralDynamic));
|
||||
tracked!(trap_unreachable, Some(false));
|
||||
tracked!(treat_err_as_bug, Some(1));
|
||||
tracked!(unleash_the_miri_inside_of_you, true);
|
||||
tracked!(use_ctors_section, Some(true));
|
||||
|
|
|
|||
|
|
@ -481,6 +481,7 @@ impl<'a> Resolver<'a> {
|
|||
name
|
||||
));
|
||||
}
|
||||
err.help("use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions");
|
||||
|
||||
err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -900,7 +900,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"emits a future-incompatibility report for lints (RFC 2834)"),
|
||||
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
|
||||
"emit a section containing stack size metadata (default: no)"),
|
||||
fewer_names: bool = (false, parse_bool, [TRACKED],
|
||||
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
|
||||
(default: no)"),
|
||||
force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
|
|
@ -1113,6 +1113,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"choose the TLS model to use (`rustc --print tls-models` for details)"),
|
||||
trace_macros: bool = (false, parse_bool, [UNTRACKED],
|
||||
"for every macro invocation, print its name and arguments (default: no)"),
|
||||
trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
|
||||
treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
|
||||
"treat error number `val` that occurs as bug"),
|
||||
trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
|
||||
|
|
|
|||
|
|
@ -734,12 +734,15 @@ impl Session {
|
|||
self.opts.cg.panic.unwrap_or(self.target.panic_strategy)
|
||||
}
|
||||
pub fn fewer_names(&self) -> bool {
|
||||
let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
|
||||
|| self.opts.output_types.contains_key(&OutputType::Bitcode)
|
||||
// AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
|
||||
|| self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
|
||||
|
||||
self.opts.debugging_opts.fewer_names || !more_names
|
||||
if let Some(fewer_names) = self.opts.debugging_opts.fewer_names {
|
||||
fewer_names
|
||||
} else {
|
||||
let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
|
||||
|| self.opts.output_types.contains_key(&OutputType::Bitcode)
|
||||
// AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
|
||||
|| self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
|
||||
!more_names
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unstable_options(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
|
|||
),
|
||||
)
|
||||
.note("the only supported types are integers, `bool` and `char`")
|
||||
.note("more complex types are supported with `#[feature(const_generics)]`")
|
||||
.help("more complex types are supported with `#[feature(const_generics)]`")
|
||||
.emit()
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for RangeMut<'_, K, V> {
|
|||
}
|
||||
|
||||
impl<K: Ord, V> BTreeMap<K, V> {
|
||||
/// Makes a new empty BTreeMap.
|
||||
/// Makes a new, empty `BTreeMap`.
|
||||
///
|
||||
/// Does not allocate anything on its own.
|
||||
///
|
||||
|
|
@ -1924,7 +1924,7 @@ impl<K: Hash, V: Hash> Hash for BTreeMap<K, V> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<K: Ord, V> Default for BTreeMap<K, V> {
|
||||
/// Creates an empty `BTreeMap<K, V>`.
|
||||
/// Creates an empty `BTreeMap`.
|
||||
fn default() -> BTreeMap<K, V> {
|
||||
BTreeMap::new()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,20 +112,8 @@ impl<K, V> InternalNode<K, V> {
|
|||
///
|
||||
/// However, `BoxedNode` contains no information as to which of the two types
|
||||
/// of nodes it actually contains, and, partially due to this lack of information,
|
||||
/// has no destructor.
|
||||
struct BoxedNode<K, V> {
|
||||
ptr: NonNull<LeafNode<K, V>>,
|
||||
}
|
||||
|
||||
impl<K, V> BoxedNode<K, V> {
|
||||
fn from_owned(ptr: NonNull<LeafNode<K, V>>) -> Self {
|
||||
BoxedNode { ptr }
|
||||
}
|
||||
|
||||
fn as_ptr(&self) -> NonNull<LeafNode<K, V>> {
|
||||
self.ptr
|
||||
}
|
||||
}
|
||||
/// is not a separate type and has no destructor.
|
||||
type BoxedNode<K, V> = NonNull<LeafNode<K, V>>;
|
||||
|
||||
/// An owned tree.
|
||||
///
|
||||
|
|
@ -168,11 +156,6 @@ impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
|
|||
pub fn borrow_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, Type> {
|
||||
NodeRef { height: self.height, node: self.node, _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Packs the reference, aware of type and height, into a type-agnostic pointer.
|
||||
fn into_boxed_node(self) -> BoxedNode<K, V> {
|
||||
BoxedNode::from_owned(self.node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
||||
|
|
@ -181,7 +164,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
|
|||
/// and is the opposite of `pop_internal_level`.
|
||||
pub fn push_internal_level(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
|
||||
let mut new_node = Box::new(unsafe { InternalNode::new() });
|
||||
new_node.edges[0].write(BoxedNode::from_owned(self.node));
|
||||
new_node.edges[0].write(self.node);
|
||||
let mut new_root = NodeRef::from_new_internal(new_node, self.height + 1);
|
||||
new_root.borrow_mut().first_edge().correct_parent_link();
|
||||
*self = new_root.forget_type();
|
||||
|
|
@ -288,13 +271,6 @@ unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::Mut<'
|
|||
unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::ValMut<'a>, K, V, Type> {}
|
||||
unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Owned, K, V, Type> {}
|
||||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
|
||||
/// Unpack a node reference that was packed by `Root::into_boxed_node`.
|
||||
fn from_boxed_node(boxed_node: BoxedNode<K, V>, height: usize) -> Self {
|
||||
NodeRef { height, node: boxed_node.as_ptr(), _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
|
||||
/// Unpack a node reference that was packed as `NodeRef::parent`.
|
||||
fn from_internal(node: NonNull<InternalNode<K, V>>, height: usize) -> Self {
|
||||
|
|
@ -695,7 +671,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
|||
unsafe {
|
||||
self.reborrow_mut().into_key_area_mut_at(idx).write(key);
|
||||
self.reborrow_mut().into_val_area_mut_at(idx).write(val);
|
||||
self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.into_boxed_node());
|
||||
self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.node);
|
||||
Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link();
|
||||
}
|
||||
}
|
||||
|
|
@ -710,7 +686,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
|
|||
*self.reborrow_mut().into_len_mut() += 1;
|
||||
slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key);
|
||||
slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val);
|
||||
slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.into_boxed_node());
|
||||
slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.node);
|
||||
}
|
||||
|
||||
self.correct_all_childrens_parent_links();
|
||||
|
|
@ -732,8 +708,8 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
|||
let edge = match self.reborrow_mut().force() {
|
||||
ForceResult::Leaf(_) => None,
|
||||
ForceResult::Internal(internal) => {
|
||||
let boxed_node = ptr::read(internal.reborrow().edge_at(idx + 1));
|
||||
let mut edge = Root::from_boxed_node(boxed_node, internal.height - 1);
|
||||
let node = ptr::read(internal.reborrow().edge_at(idx + 1));
|
||||
let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData };
|
||||
// In practice, clearing the parent is a waste of time, because we will
|
||||
// insert the node elsewhere and set its parent link again.
|
||||
edge.borrow_mut().clear_parent_link();
|
||||
|
|
@ -760,9 +736,8 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
|
|||
let edge = match self.reborrow_mut().force() {
|
||||
ForceResult::Leaf(_) => None,
|
||||
ForceResult::Internal(mut internal) => {
|
||||
let boxed_node =
|
||||
slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0);
|
||||
let mut edge = Root::from_boxed_node(boxed_node, internal.height - 1);
|
||||
let node = slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0);
|
||||
let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData };
|
||||
// In practice, clearing the parent is a waste of time, because we will
|
||||
// insert the node elsewhere and set its parent link again.
|
||||
edge.borrow_mut().clear_parent_link();
|
||||
|
|
@ -1041,12 +1016,11 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
|
|||
debug_assert!(self.node.len() < CAPACITY);
|
||||
debug_assert!(edge.height == self.node.height - 1);
|
||||
|
||||
let boxed_node = edge.into_boxed_node();
|
||||
unsafe {
|
||||
*self.node.reborrow_mut().into_len_mut() += 1;
|
||||
slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key);
|
||||
slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val);
|
||||
slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, boxed_node);
|
||||
slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, edge.node);
|
||||
|
||||
self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len());
|
||||
}
|
||||
|
|
@ -1135,8 +1109,8 @@ impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marke
|
|||
// reference (Rust issue #73987) and invalidate any other references
|
||||
// to or inside the array, should any be around.
|
||||
let parent_ptr = NodeRef::as_internal_ptr(&self.node);
|
||||
let boxed_node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() };
|
||||
NodeRef::from_boxed_node(boxed_node, self.node.height - 1)
|
||||
let node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() };
|
||||
NodeRef { node, height: self.node.height - 1, _marker: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -220,7 +220,9 @@ impl<T: fmt::Debug> fmt::Debug for Union<'_, T> {
|
|||
const ITER_PERFORMANCE_TIPPING_SIZE_DIFF: usize = 16;
|
||||
|
||||
impl<T: Ord> BTreeSet<T> {
|
||||
/// Makes a new `BTreeSet` with a reasonable choice of B.
|
||||
/// Makes a new, empty `BTreeSet`.
|
||||
///
|
||||
/// Does not allocate anything on its own.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1121,7 +1123,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet<T> {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Ord> Default for BTreeSet<T> {
|
||||
/// Makes an empty `BTreeSet<T>` with a reasonable choice of B.
|
||||
/// Creates an empty `BTreeSet`.
|
||||
fn default() -> BTreeSet<T> {
|
||||
BTreeSet::new()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1739,7 +1739,7 @@ mod super_keyword {}
|
|||
///
|
||||
/// # Differences between the 2015 and 2018 editions
|
||||
///
|
||||
/// In the 2015 edition parameters pattern where not needed for traits:
|
||||
/// In the 2015 edition the parameters pattern was not needed for traits:
|
||||
///
|
||||
/// ```rust,edition2015
|
||||
/// trait Tr {
|
||||
|
|
|
|||
|
|
@ -18,4 +18,5 @@
|
|||
- [Known Issues](targets/known-issues.md)
|
||||
- [Profile-guided Optimization](profile-guided-optimization.md)
|
||||
- [Linker-plugin based LTO](linker-plugin-lto.md)
|
||||
- [Exploit Mitigations](exploit-mitigations.md)
|
||||
- [Contributing to `rustc`](contributing.md)
|
||||
|
|
|
|||
693
src/doc/rustc/src/exploit-mitigations.md
Normal file
693
src/doc/rustc/src/exploit-mitigations.md
Normal file
|
|
@ -0,0 +1,693 @@
|
|||
# Exploit Mitigations
|
||||
|
||||
This chapter documents the exploit mitigations supported by the Rust
|
||||
compiler, and is by no means an extensive survey of the Rust programming
|
||||
language’s security features.
|
||||
|
||||
This chapter is for software engineers working with the Rust programming
|
||||
language, and assumes prior knowledge of the Rust programming language and
|
||||
its toolchain.
|
||||
|
||||
|
||||
## Introduction
|
||||
|
||||
The Rust programming language provides memory[1] and thread[2] safety
|
||||
guarantees via its ownership[3], references and borrowing[4], and slice
|
||||
types[5] features. However, Unsafe Rust[6] introduces unsafe blocks, unsafe
|
||||
functions and methods, unsafe traits, and new types that are not subject to
|
||||
the borrowing rules.
|
||||
|
||||
Parts of the Rust standard library are implemented as safe abstractions over
|
||||
unsafe code (and historically have been vulnerable to memory corruption[7]).
|
||||
Furthermore, the Rust code and documentation encourage creating safe
|
||||
abstractions over unsafe code. This can cause a false sense of security if
|
||||
unsafe code is not properly reviewed and tested.
|
||||
|
||||
Unsafe Rust introduces features that do not provide the same memory and
|
||||
thread safety guarantees. This causes programs or libraries to be
|
||||
susceptible to memory corruption (CWE-119)[8] and concurrency issues
|
||||
(CWE-557)[9]. Modern C and C++ compilers provide exploit mitigations to
|
||||
increase the difficulty to exploit vulnerabilities resulting from these
|
||||
issues. Therefore, the Rust compiler must also support these exploit
|
||||
mitigations in order to mitigate vulnerabilities resulting from the use of
|
||||
Unsafe Rust. This chapter documents these exploit mitigations and how they
|
||||
apply to Rust.
|
||||
|
||||
This chapter does not discuss the effectiveness of these exploit mitigations
|
||||
as they vary greatly depending on several factors besides their design and
|
||||
implementation, but rather describe what they do, so their effectiveness can
|
||||
be understood within a given context.
|
||||
|
||||
|
||||
## Exploit mitigations
|
||||
|
||||
This section documents the exploit mitigations applicable to the Rust
|
||||
compiler when building programs for the Linux operating system on the AMD64
|
||||
architecture and equivalent.<sup id="fnref:1" role="doc-noteref"><a
|
||||
href="#fn:1" class="footnote">1</a></sup>
|
||||
|
||||
The Rust Programming Language currently has no specification. The Rust
|
||||
compiler (i.e., rustc) is the language reference implementation. All
|
||||
references to “the Rust compiler” in this chapter refer to the language
|
||||
reference implementation.
|
||||
|
||||
Table I \
|
||||
Summary of exploit mitigations supported by the Rust compiler when building
|
||||
programs for the Linux operating system on the AMD64 architecture and
|
||||
equivalent.
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td><strong>Exploit mitigation</strong>
|
||||
</td>
|
||||
<td><strong>Supported and enabled by default</strong>
|
||||
</td>
|
||||
<td><strong>Since</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Position-independent executable
|
||||
</td>
|
||||
<td>Yes
|
||||
</td>
|
||||
<td>0.12.0 (2014-10-09)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Integer overflow checks
|
||||
</td>
|
||||
<td>Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled)
|
||||
</td>
|
||||
<td>1.1.0 (2015-06-25)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Non-executable memory regions
|
||||
</td>
|
||||
<td>Yes
|
||||
</td>
|
||||
<td>1.8.0 (2016-04-14)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stack clashing protection
|
||||
</td>
|
||||
<td>Yes
|
||||
</td>
|
||||
<td>1.20.0 (2017-08-31)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Read-only relocations and immediate binding
|
||||
</td>
|
||||
<td>Yes
|
||||
</td>
|
||||
<td>1.21.0 (2017-10-12)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Heap corruption protection
|
||||
</td>
|
||||
<td>Yes
|
||||
</td>
|
||||
<td>1.32.0 (2019-01-17) (via operating system default or specified allocator)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stack smashing protection
|
||||
</td>
|
||||
<td>No
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Forward-edge control flow protection
|
||||
</td>
|
||||
<td>No
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Backward-edge control flow protection (e.g., shadow and safe stack)
|
||||
</td>
|
||||
<td>No
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<small id="fn:1">1\. See
|
||||
<https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec>
|
||||
for a list of targets and their default options. <a href="#fnref:1"
|
||||
class="reversefootnote" role="doc-backlink">↩</a></small>
|
||||
|
||||
|
||||
### Position-independent executable
|
||||
|
||||
Position-independent executable increases the difficulty of the use of code
|
||||
reuse exploitation techniques, such as return-oriented programming (ROP) and
|
||||
variants, by generating position-independent code for the executable, and
|
||||
instructing the dynamic linker to load it similarly to a shared object at a
|
||||
random load address, thus also benefiting from address-space layout
|
||||
randomization (ASLR). This is also referred to as “full ASLR”.
|
||||
|
||||
The Rust compiler supports position-independent executable, and enables it
|
||||
by default since version 0.12.0 (2014-10-09)[10]–[13].
|
||||
|
||||
```text
|
||||
$ readelf -h target/release/hello-rust | grep Type:
|
||||
Type: DYN (Shared object file)
|
||||
```
|
||||
Fig. 1. Checking if an executable is a position-independent executable.
|
||||
|
||||
An executable with an object type of `ET_DYN` (i.e., shared object) and not
|
||||
`ET_EXEC` (i.e., executable) is a position-independent executable (see Fig.
|
||||
1).
|
||||
|
||||
|
||||
### Integer overflow checks
|
||||
|
||||
Integer overflow checks protects programs from undefined and unintended
|
||||
behavior (which may cause vulnerabilities) by checking for results of signed
|
||||
and unsigned integer computations that cannot be represented in their type,
|
||||
resulting in an overflow or wraparound.
|
||||
|
||||
The Rust compiler supports integer overflow checks, and enables it when
|
||||
debug assertions are enabled since version 1.1.0 (2015-06-25)[14]–[20].
|
||||
|
||||
```compile_fail
|
||||
fn main() {
|
||||
let u: u8 = 255;
|
||||
println!("u: {}", u + 1);
|
||||
}
|
||||
```
|
||||
Fig. 2. hello-rust-integer program.
|
||||
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling hello-rust-integer v0.1.0 (/home/rcvalle/hello-rust-integer)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.23s
|
||||
Running `target/debug/hello-rust-integer`
|
||||
thread 'main' panicked at 'attempt to add with overflow', src/main.rs:3:23
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
|
||||
```
|
||||
Fig. 3. Build and execution of hello-rust-integer with debug assertions
|
||||
enabled.
|
||||
|
||||
```text
|
||||
$ cargo run --release
|
||||
Compiling hello-rust-integer v0.1.0 (/home/rcvalle/hello-rust-integer)
|
||||
Finished release [optimized] target(s) in 0.23s
|
||||
Running `target/release/hello-rust-integer`
|
||||
u: 0
|
||||
```
|
||||
Fig. 4. Build and execution of hello-rust-integer with debug assertions
|
||||
disabled.
|
||||
|
||||
Integer overflow checks are enabled when debug assertions are enabled (see
|
||||
Fig. 3), and disabled when debug assertions are disabled (see Fig. 4). To
|
||||
enable integer overflow checks independently, use the option to control
|
||||
integer overflow checks, scoped attributes, or explicit checking methods
|
||||
such as `checked_add`<sup id="fnref:2" role="doc-noteref"><a href="#fn:2"
|
||||
class="footnote">2</a></sup>.
|
||||
|
||||
It is recommended that explicit wrapping methods such as `wrapping_add` be
|
||||
used when wrapping semantics are intended, and that explicit checking and
|
||||
wrapping methods always be used when using Unsafe Rust.
|
||||
|
||||
<small id="fn:2">2\. See <https://doc.rust-lang.org/std/primitive.u32.html>
|
||||
for more information on the checked, overflowing, saturating, and wrapping
|
||||
methods (using u32 as an example). <a href="#fnref:2"
|
||||
class="reversefootnote" role="doc-backlink">↩</a></small>
|
||||
|
||||
|
||||
### Non-executable memory regions
|
||||
|
||||
Non-executable memory regions increase the difficulty of exploitation by
|
||||
limiting the memory regions that can be used to execute arbitrary code. Most
|
||||
modern processors provide support for the operating system to mark memory
|
||||
regions as non executable, but it was previously emulated by software, such
|
||||
as in grsecurity/PaX's
|
||||
[PAGEEXEC](https://pax.grsecurity.net/docs/pageexec.txt) and
|
||||
[SEGMEXEC](https://pax.grsecurity.net/docs/segmexec.txt), on processors that
|
||||
did not provide support for it. This is also known as “No Execute (NX) Bit”,
|
||||
“Execute Disable (XD) Bit”, “Execute Never (XN) Bit”, and others.
|
||||
|
||||
The Rust compiler supports non-executable memory regions, and enables it by
|
||||
default since its initial release, version 0.1 (2012-01-20)[21], [22], but
|
||||
has regressed since then[23]–[25], and enforced by default since version
|
||||
1.8.0 (2016-04-14)[25].
|
||||
|
||||
```text
|
||||
$ readelf -l target/release/hello-rust | grep -A 1 GNU_STACK
|
||||
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
|
||||
0x0000000000000000 0x0000000000000000 RW 0x10
|
||||
```
|
||||
Fig. 5. Checking if non-executable memory regions are enabled for a given
|
||||
binary.
|
||||
|
||||
The presence of an element of type `PT_GNU_STACK` in the program header
|
||||
table with the `PF_X` (i.e., executable) flag unset indicates non-executable
|
||||
memory regions<sup id="fnref:3" role="doc-noteref"><a href="#fn:3"
|
||||
class="footnote">3</a></sup> are enabled for a given binary (see Fig. 5).
|
||||
Conversely, the presence of an element of type `PT_GNU_STACK` in the program
|
||||
header table with the `PF_X` flag set or the absence of an element of type
|
||||
`PT_GNU_STACK` in the program header table indicates non-executable memory
|
||||
regions are not enabled for a given binary.
|
||||
|
||||
<small id="fn:3">3\. See the Appendix section for more information on why it
|
||||
affects other memory regions besides the stack. <a href="#fnref:3"
|
||||
class="reversefootnote" role="doc-backlink">↩</a></small>
|
||||
|
||||
|
||||
### Stack clashing protection
|
||||
|
||||
Stack clashing protection protects the stack from overlapping with another
|
||||
memory region—allowing arbitrary data in both to be overwritten using each
|
||||
other—by reading from the stack pages as the stack grows to cause a page
|
||||
fault when attempting to read from the guard page/region. This is also
|
||||
referred to as “stack probes” or “stack probing”.
|
||||
|
||||
The Rust compiler supports stack clashing protection via stack probing, and
|
||||
enables it by default since version 1.20.0 (2017-08-31)[26]–[29].
|
||||
|
||||

|
||||
Fig. 6. IDA Pro listing cross references to `__rust_probestack` in
|
||||
hello-rust.
|
||||
|
||||
```rust
|
||||
fn hello() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: [u64; 1024] = [0; 1024];
|
||||
hello();
|
||||
}
|
||||
```
|
||||
Fig 7. Modified hello-rust.
|
||||
|
||||

|
||||
Fig. 8. IDA Pro listing cross references to `__rust_probestack` in modified
|
||||
hello-rust.
|
||||
|
||||
To check if stack clashing protection is enabled for a given binary, search
|
||||
for cross references to `__rust_probestack`. The `__rust_probestack` is
|
||||
called in the prologue of functions whose stack size is larger than a page
|
||||
size (see Fig. 6), and can be forced for illustration purposes by modifying
|
||||
the hello-rust example as seen in Fig. 7 and Fig. 8.
|
||||
|
||||
|
||||
### Read-only relocations and immediate binding
|
||||
|
||||
**Read-only relocations** protect segments containing relocations and
|
||||
relocation information (i.e., `.init_array`, `.fini_array`, `.dynamic`, and
|
||||
`.got`) from being overwritten by marking these segments read only. This is
|
||||
also referred to as “partial RELRO”.
|
||||
|
||||
The Rust compiler supports read-only relocations, and enables it by default
|
||||
since version 1.21.0 (2017-10-12)[30], [31].
|
||||
|
||||
```text
|
||||
$ readelf -l target/release/hello-rust | grep GNU_RELRO
|
||||
GNU_RELRO 0x000000000002ee00 0x000000000002fe00 0x000000000002fe00
|
||||
```
|
||||
Fig. 9. Checking if read-only relocations is enabled for a given binary.
|
||||
|
||||
The presence of an element of type `PT_GNU_RELRO` in the program header
|
||||
table indicates read-only relocations are enabled for a given binary (see
|
||||
Fig. 9). Conversely, the absence of an element of type `PT_GNU_RELRO` in the
|
||||
program header table indicates read-only relocations are not enabled for a
|
||||
given binary.
|
||||
|
||||
**Immediate binding** protects additional segments containing relocations
|
||||
(i.e., `.got.plt`) from being overwritten by instructing the dynamic linker
|
||||
to perform all relocations before transferring control to the program during
|
||||
startup, so all segments containing relocations can be marked read only
|
||||
(when combined with read-only relocations). This is also referred to as
|
||||
“full RELRO”.
|
||||
|
||||
The Rust compiler supports immediate binding, and enables it by default
|
||||
since version 1.21.0 (2017-10-12)[30], [31].
|
||||
|
||||
```text
|
||||
$ readelf -d target/release/hello-rust | grep BIND_NOW
|
||||
0x000000000000001e (FLAGS) BIND_NOW
|
||||
```
|
||||
Fig. 10. Checking if immediate binding is enabled for a given binary.
|
||||
|
||||
The presence of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW`
|
||||
flag<sup id="fnref:4" role="doc-noteref"><a href="#fn:4"
|
||||
class="footnote">4</a></sup> in the dynamic section indicates immediate
|
||||
binding is enabled for a given binary (see Fig. 10). Conversely, the absence
|
||||
of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW` flag in the
|
||||
dynamic section indicates immediate binding is not enabled for a given
|
||||
binary.
|
||||
|
||||
The presence of both an element of type `PT_GNU_RELRO` in the program header
|
||||
table and of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW`
|
||||
flag in the dynamic section indicates full RELRO is enabled for a given
|
||||
binary (see Fig. 9 and Fig. 10).
|
||||
|
||||
<small id="fn:4">4\. And the `DF_1_NOW` flag for some link editors. <a
|
||||
href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></small>
|
||||
|
||||
|
||||
### Heap corruption protection
|
||||
|
||||
Heap corruption protection protects memory allocated dynamically by
|
||||
performing several checks, such as checks for corrupted links between list
|
||||
elements, invalid pointers, invalid sizes, double/multiple “frees” of the
|
||||
same memory allocated, and many corner cases of these. These checks are
|
||||
implementation specific, and vary per allocator.
|
||||
|
||||
[ARM Memory Tagging Extension
|
||||
(MTE)](https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/enhancing-memory-safety),
|
||||
when available, will provide hardware assistance for a probabilistic
|
||||
mitigation to detect memory safety violations by tagging memory allocations,
|
||||
and automatically checking that the correct tag is used on every memory
|
||||
access.
|
||||
|
||||
Rust’s default allocator has historically been
|
||||
[jemalloc](http://jemalloc.net/), and it has long been the cause of issues
|
||||
and the subject of much discussion[32]–[38]. Consequently, it has been
|
||||
removed as the default allocator in favor of the operating system’s standard
|
||||
C library default allocator<sup id="fnref:5" role="doc-noteref"><a
|
||||
href="#fn:5" class="footnote">5</a></sup> since version 1.32.0
|
||||
(2019-01-17)[39].
|
||||
|
||||
```ignore
|
||||
fn main() {
|
||||
let mut x = Box::new([0; 1024]);
|
||||
|
||||
for i in 0..1026 {
|
||||
unsafe {
|
||||
let elem = x.get_unchecked_mut(i);
|
||||
*elem = 0x4141414141414141u64;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Fig. 11. hello-rust-heap program.
|
||||
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling hello-rust-heap v0.1.0 (/home/rcvalle/hello-rust-heap)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.25s
|
||||
Running `target/debug/hello-rust-heap`
|
||||
free(): invalid next size (normal)
|
||||
Aborted
|
||||
```
|
||||
Fig. 12. Build and execution of hello-rust-heap with debug assertions
|
||||
enabled.
|
||||
|
||||
```text
|
||||
$ cargo run --release
|
||||
Compiling hello-rust-heap v0.1.0 (/home/rcvalle/hello-rust-heap)
|
||||
Finished release [optimized] target(s) in 0.25s
|
||||
Running `target/release/hello-rust-heap`
|
||||
free(): invalid next size (normal)
|
||||
Aborted
|
||||
```
|
||||
Fig. 13. Build and execution of hello-rust-heap with debug assertions
|
||||
disabled.
|
||||
|
||||
Heap corruption checks are being performed when using the default allocator
|
||||
(i.e., the GNU Allocator) as seen in Fig. 12 and Fig. 13.
|
||||
|
||||
<small id="fn:5">5\. Linux's standard C library default allocator is the GNU
|
||||
Allocator, which is derived from ptmalloc (pthreads malloc) by Wolfram
|
||||
Gloger, which in turn is derived from dlmalloc (Doug Lea malloc) by Doug
|
||||
Lea. <a href="#fnref:5" class="reversefootnote"
|
||||
role="doc-backlink">↩</a></small>
|
||||
|
||||
|
||||
### Stack smashing protection
|
||||
|
||||
Stack smashing protection protects programs from stack-based buffer
|
||||
overflows by inserting a random guard value between local variables and the
|
||||
saved return instruction pointer, and checking if this value has changed
|
||||
when returning from a function. This is also known as “Stack Protector” or
|
||||
“Stack Smashing Protector (SSP)”.
|
||||
|
||||
The Rust compiler does not support stack smashing protection. However, more
|
||||
comprehensive alternatives to stack smashing protection exist, such as
|
||||
shadow and safe stack (see backward-edge control flow protection).
|
||||
|
||||

|
||||
Fig. 14. IDA Pro listing cross references to `__stack_chk_fail` in
|
||||
hello-rust.
|
||||
|
||||
To check if stack smashing protection is enabled for a given binary, search
|
||||
for cross references to `__stack_chk_fail`. The only cross references to
|
||||
`__stack_chk_fail` in hello-rust are from the statically-linked libbacktrace
|
||||
library (see Fig. 14).
|
||||
|
||||
|
||||
### Forward-edge control flow protection
|
||||
|
||||
Forward-edge control flow protection protects programs from having its
|
||||
control flow changed/hijacked by performing checks to ensure that
|
||||
destinations of indirect branches are one of their valid destinations in the
|
||||
control flow graph. The comprehensiveness of these checks vary per
|
||||
implementation. This is also known as “forward-edge control flow integrity
|
||||
(CFI)”.
|
||||
|
||||
Newer processors provide hardware assistance for forward-edge control flow
|
||||
protection, such as ARM Branch Target Identification (BTI), ARM Pointer
|
||||
Authentication, and Intel Indirect Branch Tracking (IBT) as part of Intel
|
||||
Control-flow Enforcement Technology (CET). However, ARM BTI and Intel IBT
|
||||
-based implementations are less comprehensive than software-based
|
||||
implementations such as [LLVM ControlFlowIntegrity
|
||||
(CFI)](https://clang.llvm.org/docs/ControlFlowIntegrity.html), and the
|
||||
commercially available [grsecurity/PaX Reuse Attack Protector
|
||||
(RAP)](https://grsecurity.net/rap_faq).
|
||||
|
||||
The Rust compiler does not support forward-edge control flow protection on
|
||||
Linux<sup id="fnref:6" role="doc-noteref"><a href="#fn:6"
|
||||
class="footnote">6</a></sup>. There is work currently ongoing to add support
|
||||
for the [sanitizers](https://github.com/google/sanitizers)[40], which may or
|
||||
may not include support for LLVM CFI.
|
||||
|
||||
```text
|
||||
$ readelf -s target/release/hello-rust | grep __cfi_init
|
||||
```
|
||||
Fig. 15. Checking if LLVM CFI is enabled for a given binary.
|
||||
|
||||
The presence of the `__cfi_init` symbol (and references to `__cfi_check`)
|
||||
indicates that LLVM CFI (i.e., forward-edge control flow protection) is
|
||||
enabled for a given binary. Conversely, the absence of the `__cfi_init`
|
||||
symbol (and references to `__cfi_check`) indicates that LLVM CFI is not
|
||||
enabled for a given binary (see Fig. 15).
|
||||
|
||||
<small id="fn:6">6\. It supports Control Flow Guard (CFG) on Windows (see
|
||||
<https://github.com/rust-lang/rust/issues/68793>). <a href="#fnref:6"
|
||||
class="reversefootnote" role="doc-backlink">↩</a></small>
|
||||
|
||||
|
||||
### Backward-edge control flow protection
|
||||
|
||||
**Shadow stack** protects saved return instruction pointers from being
|
||||
overwritten by storing a copy of them on a separate (shadow) stack, and
|
||||
using these copies as authoritative values when returning from functions.
|
||||
This is also known as “ShadowCallStack” and “Return Flow Guard”, and is
|
||||
considered an implementation of backward-edge control flow protection (or
|
||||
“backward-edge CFI”).
|
||||
|
||||
**Safe stack** protects not only the saved return instruction pointers, but
|
||||
also register spills and some local variables from being overwritten by
|
||||
storing unsafe variables, such as large arrays, on a separate (unsafe)
|
||||
stack, and using these unsafe variables on the separate stack instead. This
|
||||
is also known as “SafeStack”, and is also considered an implementation of
|
||||
backward-edge control flow protection.
|
||||
|
||||
Both shadow and safe stack are intended to be a more comprehensive
|
||||
alternatives to stack smashing protection as they protect the saved return
|
||||
instruction pointers (and other data in the case of safe stack) from
|
||||
arbitrary writes and non-linear out-of-bounds writes.
|
||||
|
||||
Newer processors provide hardware assistance for backward-edge control flow
|
||||
protection, such as ARM Pointer Authentication, and Intel Shadow Stack as
|
||||
part of Intel CET.
|
||||
|
||||
The Rust compiler does not support shadow or safe stack. There is work
|
||||
currently ongoing to add support for the sanitizers[40], which may or may
|
||||
not include support for safe stack<sup id="fnref:7" role="doc-noteref"><a
|
||||
href="#fn:7" class="footnote">7</a></sup>.
|
||||
|
||||
```text
|
||||
$ readelf -s target/release/hello-rust | grep __safestack_init
|
||||
```
|
||||
Fig. 16. Checking if LLVM SafeStack is enabled for a given binary.
|
||||
|
||||
The presence of the `__safestack_init` symbol indicates that LLVM SafeStack
|
||||
is enabled for a given binary. Conversely, the absence of the
|
||||
`__safestack_init` symbol indicates that LLVM SafeStack is not enabled for a
|
||||
given binary (see Fig. 16).
|
||||
|
||||
<small id="fn:7">7\. The shadow stack implementation for the AMD64
|
||||
architecture and equivalent in LLVM was removed due to performance and
|
||||
security issues. <a href="#fnref:7" class="reversefootnote"
|
||||
role="doc-backlink">↩</a></small>
|
||||
|
||||
|
||||
## Appendix
|
||||
|
||||
As of the latest version of the [Linux Standard Base (LSB) Core
|
||||
Specification](https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/progheader.html),
|
||||
the `PT_GNU_STACK` program header indicates whether the stack should be
|
||||
executable, and the absence of this header indicates that the stack should
|
||||
be executable. However, the Linux kernel currently sets the
|
||||
`READ_IMPLIES_EXEC` personality upon loading any executable with the
|
||||
`PT_GNU_STACK` program header and the `PF_X `flag set or with the absence of
|
||||
this header, resulting in not only the stack, but also all readable virtual
|
||||
memory mappings being executable.
|
||||
|
||||
An attempt to fix this [was made in
|
||||
2012](https://lore.kernel.org/lkml/f298f914-2239-44e4-8aa1-a51282e7fac0@zmail15.collab.prod.int.phx2.redhat.com/),
|
||||
and another [was made in
|
||||
2020](https://lore.kernel.org/kernel-hardening/20200327064820.12602-1-keescook@chromium.org/).
|
||||
The former never landed, and the latter partially fixed it, but introduced
|
||||
other issues—the absence of the `PT_GNU_STACK` program header still causes
|
||||
not only the stack, but also all readable virtual memory mappings to be
|
||||
executable in some architectures, such as IA-32 and equivalent (or causes
|
||||
the stack to be non-executable in some architectures, such as AMD64 and
|
||||
equivalent, contradicting the LSB).
|
||||
|
||||
The `READ_IMPLIES_EXEC` personality needs to be completely separated from
|
||||
the `PT_GNU_STACK` program header by having a separate option for it (or
|
||||
setarch -X could just be used whenever `READ_IMPLIES_EXEC` is needed), and
|
||||
the absence of the `PT_GNU_STACK` program header needs to have more secure
|
||||
defaults (unrelated to `READ_IMPLIES_EXEC`).
|
||||
|
||||
|
||||
## References
|
||||
|
||||
1. D. Hosfelt. “Fearless security: memory safety.” Mozilla Hacks.
|
||||
<https://hacks.mozilla.org/2019/01/fearless-security-memory-safety/>.
|
||||
|
||||
2. D. Hosfelt. “Fearless security: thread safety.” Mozilla Hacks.
|
||||
<https://hacks.mozilla.org/2019/02/fearless-security-thread-safety/>.
|
||||
|
||||
3. S. Klabnik and C. Nichols. “What Is Ownership?.” The Rust Programming
|
||||
Language. <https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html>.
|
||||
|
||||
4. S. Klabnik and C. Nichols. “References and Borrowing.” The Rust
|
||||
Programming Language.
|
||||
<https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html>.
|
||||
|
||||
5. S. Klabnik and C. Nichols. “The Slice Type.” The Rust Programming
|
||||
Language. <https://doc.rust-lang.org/book/ch04-03-slices.html>.
|
||||
|
||||
6. S. Klabnik and C. Nichols. “Unsafe Rust.” The Rust Programming Language.
|
||||
<https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html>.
|
||||
|
||||
7. S. Davidoff. “How Rust’s standard library was vulnerable for years and
|
||||
nobody noticed.” Medium.
|
||||
<https://medium.com/@shnatsel/how-rusts-standard-library-was-vulnerable-for-years-and-nobody-noticed-aebf0503c3d6>.
|
||||
|
||||
8. “Improper restriction of operations within the bounds of a memory buffer
|
||||
(CWE-119).” MITRE CWE List.
|
||||
<https://cwe.mitre.org/data/definitions/119.html>.
|
||||
|
||||
9. “Concurrency issues (CWE-557).” MITRE CWE List.
|
||||
<https://cwe.mitre.org/data/definitions/557.html>.
|
||||
|
||||
10. K. McAllister. “Memory exploit mitigations #15179.” GitHub.
|
||||
<https://github.com/rust-lang/rust/issues/15179>.
|
||||
|
||||
11. K. McAllister. “RFC: Memory exploit mitigation #145.” GitHub.
|
||||
<https://github.com/rust-lang/rfcs/pull/145>.
|
||||
|
||||
12. K. McAllister. “RFC: Memory exploit mitigation.” GitHub.
|
||||
<https://github.com/kmcallister/rfcs/blob/hardening/active/0000-memory-exploit-mitigation.md>.
|
||||
|
||||
13. D. Micay. “Enable PIE by default on Linux for full ASLR #16340.” GitHub.
|
||||
<https://github.com/rust-lang/rust/pull/16340>.
|
||||
|
||||
14. N. Matsakis. “Integer overflow #560.” GitHub.
|
||||
<https://github.com/rust-lang/rfcs/pull/560>.
|
||||
|
||||
15. G. Lehel and N. Matsakis. “Integer overflow.” GitHub.
|
||||
<https://rust-lang.github.io/rfcs/0560-integer-overflow.html>.
|
||||
|
||||
16. A. Turon. “Tracking issue for integer overflow (RFC 560) #22020.”
|
||||
GitHub. <https://github.com/rust-lang/rust/issues/22020>.
|
||||
|
||||
17. H. Wilson. “Myths and legends about integer overflow in Rust.” Huon on
|
||||
the Internet.
|
||||
<http://huonw.github.io/blog/2016/04/myths-and-legends-about-integer-overflow-in-rust/>.
|
||||
|
||||
18. B. Anderson. “Stabilize -C overflow-checks #1535.” GitHub.
|
||||
<https://github.com/rust-lang/rfcs/pull/1535>.
|
||||
|
||||
19. B. Anderson. “Stable overflow checks.” GitHub.
|
||||
<https://github.com/brson/rfcs/blob/overflow/text/0000-stable-overflow-checks.md>.
|
||||
|
||||
20. N. Froyd. “Add -C overflow-checks option #40037.” GitHub.
|
||||
<https://github.com/rust-lang/rust/pull/40037>.
|
||||
|
||||
21. R. Á. de Espíndola. “rustc requires executable stack #798.” GitHub.
|
||||
<https://github.com/rust-lang/rust/issues/798>.
|
||||
|
||||
22. A. Seipp. “Make sure librustrt.so is linked with a non-executable stack.
|
||||
#1066.” GitHub. <https://github.com/rust-lang/rust/pull/1066>.
|
||||
|
||||
23. D. Micay. “Rust binaries should not have an executable stack #5643.”
|
||||
GitHub. <https://github.com/rust-lang/rust/issues/5643>.
|
||||
|
||||
24. D. Micay. “Mark the assembly object stacks as non-executable #5647.”
|
||||
GitHub. <https://github.com/rust-lang/rust/pull/5647>.
|
||||
|
||||
25. A. Clark. “Explicitly disable stack execution on linux and bsd #30859.”
|
||||
GitHub. <https://github.com/rust-lang/rust/pull/30859>.
|
||||
|
||||
26. “Replace stack overflow checking with stack probes #16012.” GitHub.
|
||||
<https://github.com/rust-lang/rust/issues/16012>.
|
||||
|
||||
27. B. Striegel. “Extend stack probe support to non-tier-1 platforms, and
|
||||
clarify policy for mitigating LLVM-dependent unsafety #43241.” GitHub.
|
||||
<https://github.com/rust-lang/rust/issues/43241>.
|
||||
|
||||
28. A. Crichton. “rustc: Implement stack probes for x86 #42816.” GitHub.
|
||||
<https://github.com/rust-lang/rust/pull/42816>.
|
||||
|
||||
29. A. Crichton. “Add \_\_rust\_probestack intrinsic #175.” GitHub.
|
||||
<https://github.com/rust-lang/compiler-builtins/pull/175>.
|
||||
|
||||
30. B. Anderson. “Consider applying -Wl,-z,relro or -Wl,-z,relro,-z,now by
|
||||
default #29877.” GitHub. <https://github.com/rust-lang/rust/issues/29877>.
|
||||
|
||||
31. J. Löthberg. “Add support for full RELRO #43170.” GitHub.
|
||||
<https://github.com/rust-lang/rust/pull/43170>.
|
||||
|
||||
32. N. Matsakis. “Allocators in Rust.” Baby Steps.
|
||||
<http://smallcultfollowing.com/babysteps/blog/2014/11/14/allocators-in-rust/>.
|
||||
|
||||
33. A. Crichton. “RFC: Allow changing the default allocator #1183.” GitHub.
|
||||
<https://github.com/rust-lang/rfcs/pull/1183>.
|
||||
|
||||
34. A. Crichton. “RFC: Swap out jemalloc.” GitHub.
|
||||
<https://rust-lang.github.io/rfcs/1183-swap-out-jemalloc.html>.
|
||||
|
||||
35. A. Crichton. “Tracking issue for changing the global, default allocator
|
||||
(RFC 1974) #27389.” GitHub.
|
||||
<https://github.com/rust-lang/rust/issues/27389>.
|
||||
|
||||
36. S. Fackler. “Prepare global allocators for stabilization #1974.” GitHub.
|
||||
<https://github.com/rust-lang/rfcs/pull/1974>.
|
||||
|
||||
37. A. Crichton. “RFC: Global allocators.” GitHub.
|
||||
<https://rust-lang.github.io/rfcs/1974-global-allocators.html>.
|
||||
|
||||
38. B. Anderson. “Switch the default global allocator to System, remove
|
||||
alloc\_jemalloc, use jemallocator in rustc #36963.” GitHub.
|
||||
<https://github.com/rust-lang/rust/issues/36963>.
|
||||
|
||||
39. A. Crichton. “Remove the alloc\_jemalloc crate #55238.” GitHub.
|
||||
<https://github.com/rust-lang/rust/pull/55238>.
|
||||
|
||||
40. J. Aparicio. 2017. “Tracking issue for sanitizer support #39699.”
|
||||
<https://github.com/rust-lang/rust/issues/39699>.
|
||||
BIN
src/doc/rustc/src/images/image1.png
Normal file
BIN
src/doc/rustc/src/images/image1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
src/doc/rustc/src/images/image2.png
Normal file
BIN
src/doc/rustc/src/images/image2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
src/doc/rustc/src/images/image3.png
Normal file
BIN
src/doc/rustc/src/images/image3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
|
|
@ -216,6 +216,10 @@ def children_of_btree_map(map):
|
|||
internal_type = lookup_type(internal_type_name)
|
||||
return node.cast(internal_type.pointer())
|
||||
|
||||
if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"):
|
||||
# BACKCOMPAT: rust 1.49
|
||||
node_ptr = node_ptr["ptr"]
|
||||
node_ptr = unwrap_unique_or_non_null(node_ptr)
|
||||
leaf = node_ptr.dereference()
|
||||
keys = leaf["keys"]
|
||||
vals = leaf["vals"]
|
||||
|
|
@ -224,9 +228,8 @@ def children_of_btree_map(map):
|
|||
|
||||
for i in xrange(0, length + 1):
|
||||
if height > 0:
|
||||
boxed_child_node = edges[i]["value"]["value"]
|
||||
child_node = unwrap_unique_or_non_null(boxed_child_node["ptr"])
|
||||
for child in children_of_node(child_node, height - 1):
|
||||
child_ptr = edges[i]["value"]["value"]
|
||||
for child in children_of_node(child_ptr, height - 1):
|
||||
yield child
|
||||
if i < length:
|
||||
# Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays.
|
||||
|
|
@ -239,9 +242,6 @@ def children_of_btree_map(map):
|
|||
if root.type.name.startswith("core::option::Option<"):
|
||||
root = root.cast(gdb.lookup_type(root.type.name[21:-1]))
|
||||
node_ptr = root["node"]
|
||||
if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"):
|
||||
node_ptr = node_ptr["ptr"]
|
||||
node_ptr = unwrap_unique_or_non_null(node_ptr)
|
||||
height = root["height"]
|
||||
for child in children_of_node(node_ptr, height):
|
||||
yield child
|
||||
|
|
|
|||
|
|
@ -234,9 +234,8 @@ impl Clean<Item> for doctree::Module<'_> {
|
|||
items.extend(self.fns.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.foreigns.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.mods.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.items.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.items.iter().map(|x| x.clean(cx)).flatten());
|
||||
items.extend(self.traits.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
|
||||
items.extend(self.macros.iter().map(|x| x.clean(cx)));
|
||||
items.extend(self.proc_macros.iter().map(|x| x.clean(cx)));
|
||||
|
||||
|
|
@ -1922,8 +1921,8 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for (&hir::Item<'_>, Option<Ident>) {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Ident>) {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
|
||||
use hir::ItemKind;
|
||||
|
||||
let (item, renamed) = self;
|
||||
|
|
@ -1977,10 +1976,11 @@ impl Clean<Item> for (&hir::Item<'_>, Option<Ident>) {
|
|||
fields: variant_data.fields().clean(cx),
|
||||
fields_stripped: false,
|
||||
}),
|
||||
ItemKind::Impl { .. } => return clean_impl(item, cx),
|
||||
_ => unreachable!("not yet converted"),
|
||||
};
|
||||
|
||||
Item::from_def_id_and_parts(def_id, Some(name), kind, cx)
|
||||
vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2005,57 +2005,53 @@ impl Clean<ImplPolarity> for ty::ImplPolarity {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clean<Vec<Item>> for doctree::Impl<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
|
||||
let mut ret = Vec::new();
|
||||
let trait_ = self.trait_.clean(cx);
|
||||
let items = self.items.iter().map(|ii| ii.clean(cx)).collect::<Vec<_>>();
|
||||
let def_id = cx.tcx.hir().local_def_id(self.id);
|
||||
|
||||
// If this impl block is an implementation of the Deref trait, then we
|
||||
// need to try inlining the target's inherent impl blocks as well.
|
||||
if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
|
||||
build_deref_target_impls(cx, &items, &mut ret);
|
||||
fn clean_impl(impl_: &hir::Item<'_>, cx: &DocContext<'_>) -> Vec<Item> {
|
||||
let mut ret = Vec::new();
|
||||
let (trait_, items, for_, unsafety, generics) = match &impl_.kind {
|
||||
hir::ItemKind::Impl { of_trait, items, self_ty, unsafety, generics, .. } => {
|
||||
(of_trait, items, self_ty, *unsafety, generics)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let trait_ = trait_.clean(cx);
|
||||
let items = items.iter().map(|ii| cx.tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
|
||||
let def_id = cx.tcx.hir().local_def_id(impl_.hir_id);
|
||||
|
||||
let provided: FxHashSet<String> = trait_
|
||||
.def_id()
|
||||
.map(|did| {
|
||||
cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let for_ = self.for_.clean(cx);
|
||||
let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) {
|
||||
DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)),
|
||||
_ => None,
|
||||
});
|
||||
let make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| Item {
|
||||
name: None,
|
||||
attrs: self.attrs.clean(cx),
|
||||
source: self.span.clean(cx),
|
||||
def_id: def_id.to_def_id(),
|
||||
visibility: self.vis.clean(cx),
|
||||
stability: cx.stability(self.id),
|
||||
deprecation: cx.deprecation(self.id).clean(cx),
|
||||
kind: ImplItem(Impl {
|
||||
unsafety: self.unsafety,
|
||||
generics: self.generics.clean(cx),
|
||||
provided_trait_methods: provided.clone(),
|
||||
trait_,
|
||||
for_,
|
||||
items,
|
||||
polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)),
|
||||
synthetic: false,
|
||||
blanket_impl: None,
|
||||
}),
|
||||
};
|
||||
if let Some(type_alias) = type_alias {
|
||||
ret.push(make_item(trait_.clone(), type_alias, items.clone()));
|
||||
}
|
||||
ret.push(make_item(trait_, for_, items));
|
||||
ret
|
||||
// If this impl block is an implementation of the Deref trait, then we
|
||||
// need to try inlining the target's inherent impl blocks as well.
|
||||
if trait_.def_id() == cx.tcx.lang_items().deref_trait() {
|
||||
build_deref_target_impls(cx, &items, &mut ret);
|
||||
}
|
||||
|
||||
let provided: FxHashSet<String> = trait_
|
||||
.def_id()
|
||||
.map(|did| cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
let for_ = for_.clean(cx);
|
||||
let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) {
|
||||
DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)),
|
||||
_ => None,
|
||||
});
|
||||
let make_item = |trait_: Option<Type>, for_: Type, items: Vec<Item>| {
|
||||
let kind = ImplItem(Impl {
|
||||
unsafety,
|
||||
generics: generics.clean(cx),
|
||||
provided_trait_methods: provided.clone(),
|
||||
trait_,
|
||||
for_,
|
||||
items,
|
||||
polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)),
|
||||
synthetic: false,
|
||||
blanket_impl: None,
|
||||
});
|
||||
Item::from_hir_id_and_parts(impl_.hir_id, None, kind, cx)
|
||||
};
|
||||
if let Some(type_alias) = type_alias {
|
||||
ret.push(make_item(trait_.clone(), type_alias, items.clone()));
|
||||
}
|
||||
ret.push(make_item(trait_, for_, items));
|
||||
ret
|
||||
}
|
||||
|
||||
impl Clean<Vec<Item>> for doctree::ExternCrate<'_> {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use rustc_attr as attr;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::{self, Lrc};
|
||||
use rustc_driver::abort_on_err;
|
||||
|
|
@ -156,21 +155,6 @@ impl<'tcx> DocContext<'tcx> {
|
|||
def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
|
||||
}
|
||||
}
|
||||
|
||||
crate fn stability(&self, id: HirId) -> Option<attr::Stability> {
|
||||
self.tcx
|
||||
.hir()
|
||||
.opt_local_def_id(id)
|
||||
.and_then(|def_id| self.tcx.lookup_stability(def_id.to_def_id()))
|
||||
.cloned()
|
||||
}
|
||||
|
||||
crate fn deprecation(&self, id: HirId) -> Option<attr::Deprecation> {
|
||||
self.tcx
|
||||
.hir()
|
||||
.opt_local_def_id(id)
|
||||
.and_then(|def_id| self.tcx.lookup_deprecation(def_id.to_def_id()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ crate struct Module<'hir> {
|
|||
// (item, renamed)
|
||||
crate items: Vec<(&'hir hir::Item<'hir>, Option<Ident>)>,
|
||||
crate traits: Vec<Trait<'hir>>,
|
||||
crate impls: Vec<Impl<'hir>>,
|
||||
crate foreigns: Vec<ForeignItem<'hir>>,
|
||||
crate macros: Vec<Macro>,
|
||||
crate proc_macros: Vec<ProcMacro>,
|
||||
|
|
@ -44,7 +43,6 @@ impl Module<'hir> {
|
|||
mods: Vec::new(),
|
||||
items: Vec::new(),
|
||||
traits: Vec::new(),
|
||||
impls: Vec::new(),
|
||||
foreigns: Vec::new(),
|
||||
macros: Vec::new(),
|
||||
proc_macros: Vec::new(),
|
||||
|
|
@ -89,22 +87,6 @@ crate struct Trait<'hir> {
|
|||
crate id: hir::HirId,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
crate struct Impl<'hir> {
|
||||
crate unsafety: hir::Unsafety,
|
||||
crate polarity: hir::ImplPolarity,
|
||||
crate defaultness: hir::Defaultness,
|
||||
crate constness: hir::Constness,
|
||||
crate generics: &'hir hir::Generics<'hir>,
|
||||
crate trait_: &'hir Option<hir::TraitRef<'hir>>,
|
||||
crate for_: &'hir hir::Ty<'hir>,
|
||||
crate items: Vec<&'hir hir::ImplItem<'hir>>,
|
||||
crate attrs: &'hir [ast::Attribute],
|
||||
crate span: Span,
|
||||
crate vis: &'hir hir::Visibility<'hir>,
|
||||
crate id: hir::HirId,
|
||||
}
|
||||
|
||||
crate struct ForeignItem<'hir> {
|
||||
crate id: hir::HirId,
|
||||
crate name: Symbol,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ impl StripItem {
|
|||
|
||||
crate trait DocFolder: Sized {
|
||||
fn fold_item(&mut self, item: Item) -> Option<Item> {
|
||||
self.fold_item_recur(item)
|
||||
Some(self.fold_item_recur(item))
|
||||
}
|
||||
|
||||
/// don't override!
|
||||
|
|
@ -71,15 +71,12 @@ crate trait DocFolder: Sized {
|
|||
}
|
||||
|
||||
/// don't override!
|
||||
fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
|
||||
let Item { attrs, name, source, visibility, def_id, kind, stability, deprecation } = item;
|
||||
|
||||
let kind = match kind {
|
||||
fn fold_item_recur(&mut self, mut item: Item) -> Item {
|
||||
item.kind = match item.kind {
|
||||
StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)),
|
||||
_ => self.fold_inner_recur(kind),
|
||||
_ => self.fold_inner_recur(item.kind),
|
||||
};
|
||||
|
||||
Some(Item { attrs, name, source, kind, visibility, stability, deprecation, def_id })
|
||||
item
|
||||
}
|
||||
|
||||
fn fold_mod(&mut self, m: Module) -> Module {
|
||||
|
|
|
|||
|
|
@ -421,55 +421,52 @@ impl DocFolder for Cache {
|
|||
|
||||
// Once we've recursively found all the generics, hoard off all the
|
||||
// implementations elsewhere.
|
||||
let ret = self.fold_item_recur(item).and_then(|item| {
|
||||
if let clean::Item { kind: clean::ImplItem(_), .. } = item {
|
||||
// Figure out the id of this impl. This may map to a
|
||||
// primitive rather than always to a struct/enum.
|
||||
// Note: matching twice to restrict the lifetime of the `i` borrow.
|
||||
let mut dids = FxHashSet::default();
|
||||
if let clean::Item { kind: clean::ImplItem(ref i), .. } = item {
|
||||
match i.for_ {
|
||||
clean::ResolvedPath { did, .. }
|
||||
| clean::BorrowedRef {
|
||||
type_: box clean::ResolvedPath { did, .. }, ..
|
||||
} => {
|
||||
let item = self.fold_item_recur(item);
|
||||
let ret = if let clean::Item { kind: clean::ImplItem(_), .. } = item {
|
||||
// Figure out the id of this impl. This may map to a
|
||||
// primitive rather than always to a struct/enum.
|
||||
// Note: matching twice to restrict the lifetime of the `i` borrow.
|
||||
let mut dids = FxHashSet::default();
|
||||
if let clean::Item { kind: clean::ImplItem(ref i), .. } = item {
|
||||
match i.for_ {
|
||||
clean::ResolvedPath { did, .. }
|
||||
| clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => {
|
||||
dids.insert(did);
|
||||
}
|
||||
ref t => {
|
||||
let did = t
|
||||
.primitive_type()
|
||||
.and_then(|t| self.primitive_locations.get(&t).cloned());
|
||||
|
||||
if let Some(did) = did {
|
||||
dids.insert(did);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
|
||||
for bound in generics {
|
||||
if let Some(did) = bound.def_id() {
|
||||
dids.insert(did);
|
||||
}
|
||||
ref t => {
|
||||
let did = t
|
||||
.primitive_type()
|
||||
.and_then(|t| self.primitive_locations.get(&t).cloned());
|
||||
|
||||
if let Some(did) = did {
|
||||
dids.insert(did);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
|
||||
for bound in generics {
|
||||
if let Some(did) = bound.def_id() {
|
||||
dids.insert(did);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
let impl_item = Impl { impl_item: item };
|
||||
if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
|
||||
for did in dids {
|
||||
self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
|
||||
}
|
||||
} else {
|
||||
let trait_did = impl_item.trait_did().expect("no trait did");
|
||||
self.orphan_trait_impls.push((trait_did, dids, impl_item));
|
||||
}
|
||||
None
|
||||
} else {
|
||||
Some(item)
|
||||
unreachable!()
|
||||
};
|
||||
let impl_item = Impl { impl_item: item };
|
||||
if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
|
||||
for did in dids {
|
||||
self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
|
||||
}
|
||||
} else {
|
||||
let trait_did = impl_item.trait_did().expect("no trait did");
|
||||
self.orphan_trait_impls.push((trait_did, dids, impl_item));
|
||||
}
|
||||
});
|
||||
None
|
||||
} else {
|
||||
Some(item)
|
||||
};
|
||||
|
||||
if pushed {
|
||||
self.stack.pop().expect("stack already empty");
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ impl<'a> DocFolder for SourceCollector<'a> {
|
|||
}
|
||||
};
|
||||
}
|
||||
self.fold_item_recur(item)
|
||||
Some(self.fold_item_recur(item))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -268,6 +268,6 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
self.fold_item_recur(i)
|
||||
Some(self.fold_item_recur(i))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
self.fold_item_recur(item)
|
||||
Some(self.fold_item_recur(item))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ struct Collapser;
|
|||
impl fold::DocFolder for Collapser {
|
||||
fn fold_item(&mut self, mut i: Item) -> Option<Item> {
|
||||
i.attrs.collapse_doc_comments();
|
||||
self.fold_item_recur(i)
|
||||
Some(self.fold_item_recur(i))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -858,7 +858,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
|
|||
// we don't display docs on `extern crate` items anyway, so don't process them.
|
||||
clean::ExternCrateItem(..) => {
|
||||
debug!("ignoring extern crate item {:?}", item.def_id);
|
||||
return self.fold_item_recur(item);
|
||||
return Some(self.fold_item_recur(item));
|
||||
}
|
||||
clean::ImportItem(Import { kind: clean::ImportKind::Simple(ref name, ..), .. }) => {
|
||||
Some(name.clone())
|
||||
|
|
@ -958,7 +958,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if item.is_mod() {
|
||||
Some(if item.is_mod() {
|
||||
if !item.attrs.inner_docs {
|
||||
self.mod_ids.push(item.def_id);
|
||||
}
|
||||
|
|
@ -968,7 +968,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
|
|||
ret
|
||||
} else {
|
||||
self.fold_item_recur(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1022,7 +1022,7 @@ impl LinkCollector<'_, '_> {
|
|||
(link.trim(), None)
|
||||
};
|
||||
|
||||
if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, ".contains(ch))) {
|
||||
if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !".contains(ch))) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
self.fold_item_recur(i)
|
||||
Some(self.fold_item_recur(i))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ impl DocFolder for ItemCollector {
|
|||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||
self.items.insert(i.def_id);
|
||||
|
||||
self.fold_item_recur(i)
|
||||
Some(self.fold_item_recur(i))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> {
|
|||
|
||||
look_for_tests(&cx, &dox, &item);
|
||||
|
||||
self.fold_item_recur(item)
|
||||
Some(self.fold_item_recur(item))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> {
|
|||
Some(hir_id) => hir_id,
|
||||
None => {
|
||||
// If non-local, no need to check anything.
|
||||
return self.fold_item_recur(item);
|
||||
return Some(self.fold_item_recur(item));
|
||||
}
|
||||
};
|
||||
let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
|
||||
|
|
@ -223,6 +223,6 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
self.fold_item_recur(item)
|
||||
Some(self.fold_item_recur(item))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> {
|
|||
Some(hir_id) => hir_id,
|
||||
None => {
|
||||
// If non-local, no need to check anything.
|
||||
return self.fold_item_recur(item);
|
||||
return Some(self.fold_item_recur(item));
|
||||
}
|
||||
};
|
||||
let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
|
||||
|
|
@ -133,6 +133,6 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
self.fold_item_recur(item)
|
||||
Some(self.fold_item_recur(item))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,6 @@ impl DocFolder for CfgPropagator {
|
|||
let result = self.fold_item_recur(item);
|
||||
self.parent_cfg = old_parent_cfg;
|
||||
|
||||
result
|
||||
Some(result)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ impl<'a> DocFolder for Stripper<'a> {
|
|||
// strip things like impl methods but when doing so
|
||||
// we must not add any items to the `retained` set.
|
||||
let old = mem::replace(&mut self.update_retained, false);
|
||||
let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
|
||||
let ret = StripItem(self.fold_item_recur(i)).strip();
|
||||
self.update_retained = old;
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -58,6 +58,6 @@ impl<'a> DocFolder for Stripper<'a> {
|
|||
self.retained.insert(i.def_id);
|
||||
}
|
||||
}
|
||||
self.fold_item_recur(i)
|
||||
Some(self.fold_item_recur(i))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ impl<'a> DocFolder for Stripper<'a> {
|
|||
let old = mem::replace(&mut self.update_retained, false);
|
||||
let ret = self.fold_item_recur(i);
|
||||
self.update_retained = old;
|
||||
return ret;
|
||||
return Some(ret);
|
||||
}
|
||||
// These items can all get re-exported
|
||||
clean::OpaqueTyItem(..)
|
||||
|
|
@ -59,7 +59,7 @@ impl<'a> DocFolder for Stripper<'a> {
|
|||
if i.def_id.is_local() && !i.visibility.is_public() {
|
||||
debug!("Stripper: stripping module {:?}", i.name);
|
||||
let old = mem::replace(&mut self.update_retained, false);
|
||||
let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
|
||||
let ret = StripItem(self.fold_item_recur(i)).strip();
|
||||
self.update_retained = old;
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -107,12 +107,10 @@ impl<'a> DocFolder for Stripper<'a> {
|
|||
self.fold_item_recur(i)
|
||||
};
|
||||
|
||||
if let Some(ref i) = i {
|
||||
if self.update_retained {
|
||||
self.retained.insert(i.def_id);
|
||||
}
|
||||
if self.update_retained {
|
||||
self.retained.insert(i.def_id);
|
||||
}
|
||||
i
|
||||
Some(i)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +151,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.fold_item_recur(i)
|
||||
Some(self.fold_item_recur(i))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -164,7 +162,7 @@ impl DocFolder for ImportStripper {
|
|||
fn fold_item(&mut self, i: Item) -> Option<Item> {
|
||||
match i.kind {
|
||||
clean::ExternCrateItem(..) | clean::ImportItem(..) if !i.visibility.is_public() => None,
|
||||
_ => self.fold_item_recur(i),
|
||||
_ => Some(self.fold_item_recur(i)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ struct CommentCleaner;
|
|||
impl fold::DocFolder for CommentCleaner {
|
||||
fn fold_item(&mut self, mut i: Item) -> Option<Item> {
|
||||
i.attrs.unindent_doc_comments();
|
||||
self.fold_item_recur(i)
|
||||
Some(self.fold_item_recur(i))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -401,37 +401,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
};
|
||||
om.traits.push(t);
|
||||
}
|
||||
hir::ItemKind::Impl {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
defaultness_span: _,
|
||||
ref generics,
|
||||
ref of_trait,
|
||||
self_ty,
|
||||
ref items,
|
||||
} => {
|
||||
hir::ItemKind::Impl { ref of_trait, .. } => {
|
||||
// Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
|
||||
// them up regardless of where they're located.
|
||||
if !self.inlining && of_trait.is_none() {
|
||||
let items =
|
||||
items.iter().map(|item| self.cx.tcx.hir().impl_item(item.id)).collect();
|
||||
let i = Impl {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
generics,
|
||||
trait_: of_trait,
|
||||
for_: self_ty,
|
||||
items,
|
||||
attrs: &item.attrs,
|
||||
id: item.hir_id,
|
||||
span: item.span,
|
||||
vis: &item.vis,
|
||||
};
|
||||
om.impls.push(i);
|
||||
om.items.push((item, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
20
src/test/codegen/fewer-names.rs
Normal file
20
src/test/codegen/fewer-names.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// no-system-llvm
|
||||
// compile-flags: -Coverflow-checks=no -O
|
||||
// revisions: YES NO
|
||||
// [YES]compile-flags: -Zfewer-names=yes
|
||||
// [NO] compile-flags: -Zfewer-names=no
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[no_mangle]
|
||||
pub fn sum(x: u32, y: u32) -> u32 {
|
||||
// YES-LABEL: define i32 @sum(i32 %0, i32 %1)
|
||||
// YES-NEXT: %3 = add i32 %1, %0
|
||||
// YES-NEXT: ret i32 %3
|
||||
|
||||
// NO-LABEL: define i32 @sum(i32 %x, i32 %y)
|
||||
// NO-NEXT: start:
|
||||
// NO-NEXT: %z = add i32 %y, %x
|
||||
// NO-NEXT: ret i32 %z
|
||||
let z = x + y;
|
||||
z
|
||||
}
|
||||
|
|
@ -106,6 +106,15 @@ LL | /// [S!]
|
|||
| this link resolves to the struct `S`, which is not in the macro namespace
|
||||
| help: to link to the struct, prefix with `struct@`: `struct@S`
|
||||
|
||||
error: unresolved link to `S::h`
|
||||
--> $DIR/intra-link-errors.rs:78:6
|
||||
|
|
||||
LL | /// [type@S::h]
|
||||
| ^^^^^^^^^
|
||||
| |
|
||||
| this link resolves to the associated function `h`, which is not in the type namespace
|
||||
| help: to link to the associated function, add parentheses: `S::h()`
|
||||
|
||||
error: unresolved link to `T::g`
|
||||
--> $DIR/intra-link-errors.rs:86:6
|
||||
|
|
||||
|
|
@ -121,15 +130,6 @@ error: unresolved link to `T::h`
|
|||
LL | /// [T::h!]
|
||||
| ^^^^^ the trait `T` has no macro named `h`
|
||||
|
||||
error: unresolved link to `S::h`
|
||||
--> $DIR/intra-link-errors.rs:78:6
|
||||
|
|
||||
LL | /// [type@S::h]
|
||||
| ^^^^^^^^^
|
||||
| |
|
||||
| this link resolves to the associated function `h`, which is not in the type namespace
|
||||
| help: to link to the associated function, add parentheses: `S::h()`
|
||||
|
||||
error: unresolved link to `m`
|
||||
--> $DIR/intra-link-errors.rs:98:6
|
||||
|
|
||||
|
|
|
|||
|
|
@ -15,8 +15,11 @@
|
|||
// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option<T>'
|
||||
|
||||
//! We should also try linking to [`Result<T, E>`]; it has *two* generics!
|
||||
//! And [`Result<T, !>`] and [`Result<!, E>`].
|
||||
//!
|
||||
// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, E>'
|
||||
// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, !>'
|
||||
// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<!, E>'
|
||||
|
||||
//! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it
|
||||
//! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()].
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/array-size-in-generic-struct-param.rs:20:15
|
||||
|
|
@ -13,6 +14,7 @@ LL | arr: [u8; CFG.arr_size],
|
|||
| ^^^ cannot perform const operation using `CFG`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `CFG`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: `Config` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/array-size-in-generic-struct-param.rs:18:21
|
||||
|
|
@ -21,7 +23,7 @@ LL | struct B<const CFG: Config> {
|
|||
| ^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | let _: [u8; foo::<T>()];
|
|||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/const-arg-in-const-arg.rs:15:23
|
||||
|
|
@ -13,6 +14,7 @@ LL | let _: [u8; bar::<N>()];
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/const-arg-in-const-arg.rs:25:23
|
||||
|
|
@ -21,6 +23,7 @@ LL | let _ = [0; bar::<N>()];
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/const-arg-in-const-arg.rs:30:24
|
||||
|
|
@ -29,6 +32,7 @@ LL | let _: Foo<{ foo::<T>() }>;
|
|||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/const-arg-in-const-arg.rs:31:24
|
||||
|
|
@ -37,6 +41,7 @@ LL | let _: Foo<{ bar::<N>() }>;
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/const-arg-in-const-arg.rs:36:27
|
||||
|
|
@ -45,6 +50,7 @@ LL | let _ = Foo::<{ foo::<T>() }>;
|
|||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/const-arg-in-const-arg.rs:37:27
|
||||
|
|
@ -53,6 +59,7 @@ LL | let _ = Foo::<{ bar::<N>() }>;
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error[E0658]: a non-static lifetime is not allowed in a `const`
|
||||
--> $DIR/const-arg-in-const-arg.rs:16:23
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | pad: [u8; is_zst::<T>()],
|
|||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||
--> $DIR/const-argument-if-length.rs:17:12
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ LL | fn bar<const X: (), 'a>(_: &'a ()) {
|
|||
| ^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `()` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/const-param-before-other-params.rs:11:17
|
||||
|
|
@ -26,7 +26,7 @@ LL | fn foo<const X: (), T>(_: &T) {}
|
|||
| ^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ LL | struct A<const N: &u8>;
|
|||
| ^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `&'static u8` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/const-param-elided-lifetime.rs:16:15
|
||||
|
|
@ -44,7 +44,7 @@ LL | impl<const N: &u8> A<N> {
|
|||
| ^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `&'static u8` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/const-param-elided-lifetime.rs:24:15
|
||||
|
|
@ -53,7 +53,7 @@ LL | impl<const N: &u8> B for A<N> {}
|
|||
| ^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `&'static u8` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/const-param-elided-lifetime.rs:28:17
|
||||
|
|
@ -62,7 +62,7 @@ LL | fn bar<const N: &u8>() {}
|
|||
| ^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `&'static u8` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/const-param-elided-lifetime.rs:19:21
|
||||
|
|
@ -71,7 +71,7 @@ LL | fn foo<const M: &u8>(&self) {}
|
|||
| ^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
|
|||
| ^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `[u8; _]` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/const-param-type-depends-on-const-param.rs:16:35
|
||||
|
|
@ -26,7 +26,7 @@ LL | pub struct SelfDependent<const N: [u8; N]>;
|
|||
| ^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | type Arr<const N: usize> = [u8; N - 1];
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/simple.rs:8:35
|
||||
|
|
@ -13,6 +14,7 @@ LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | type Arr<const N: usize> = [u8; N - 1];
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | struct Const<const V: [usize; 1]> {}
|
|||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | struct B<const X: A>; // ok
|
|||
| ^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `C` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/forbid-non-structural_match-types.rs:15:19
|
||||
|
|
@ -14,7 +14,7 @@ LL | struct D<const X: C>;
|
|||
| ^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error[E0741]: `C` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
|
||||
--> $DIR/forbid-non-structural_match-types.rs:15:19
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | fn bar<const N: usize>() -> [u32; foo(N)] {
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/generic-function-call-in-array-length.rs:12:13
|
||||
|
|
@ -13,6 +14,7 @@ LL | [0; foo(N)]
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
|
|||
| ^ cannot perform const operation using `A`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `A`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/generic-sum-in-array-length.rs:7:57
|
||||
|
|
@ -13,6 +14,7 @@ LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
|
|||
| ^ cannot perform const operation using `B`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `B`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | T: Trait<{std::intrinsics::type_name::<T>()}>
|
|||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: `&'static str` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/intrinsics-type_name-as-const-argument.rs:10:22
|
||||
|
|
@ -13,7 +14,7 @@ LL | trait Trait<const S: &'static str> {}
|
|||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
|
|||
| ^^^^^ cannot perform const operation using `COUNT`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `COUNT`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/issue-61522-array-len-succ.rs:12:30
|
||||
|
|
@ -13,6 +14,7 @@ LL | fn inner(&self) -> &[u8; COUNT + 1] {
|
|||
| ^^^^^ cannot perform const operation using `COUNT`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `COUNT`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | trait Trait<const NAME: &'static str> {
|
|||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | inner: [(); { [|_: &T| {}; 0].len() }],
|
|||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error[E0392]: parameter `T` is never used
|
||||
--> $DIR/issue-67375.rs:7:12
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | let x: S = MaybeUninit::uninit();
|
|||
| ^ cannot perform const operation using `S`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/issue-67945-1.rs:17:45
|
||||
|
|
@ -13,6 +14,7 @@ LL | let b = &*(&x as *const _ as *const S);
|
|||
| ^ cannot perform const operation using `S`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error[E0392]: parameter `S` is never used
|
||||
--> $DIR/issue-67945-1.rs:11:12
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | let x: S = MaybeUninit::uninit();
|
|||
| ^ cannot perform const operation using `S`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/issue-67945-2.rs:15:45
|
||||
|
|
@ -13,6 +14,7 @@ LL | let b = &*(&x as *const _ as *const S);
|
|||
| ^ cannot perform const operation using `S`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error[E0392]: parameter `S` is never used
|
||||
--> $DIR/issue-67945-2.rs:9:12
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | fn successor() -> Const<{C + 1}> {
|
|||
| ^ cannot perform const operation using `C`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `C`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | Self:FooImpl<{N==0}>
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | let _ = [0u64; N + 1];
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | fn foo<const T: NoMatch>() -> bool {
|
|||
| ^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ LL | fn foo<const N: usize, const A: [u8; N]>() {}
|
|||
| ^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | fn test<const T: &'static dyn A>() {
|
|||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
|
||||
--> $DIR/issue-63322-forbid-dyn.rs:10:18
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
|
|||
| ^^^^^^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/issue-64494.rs:19:38
|
||||
|
|
@ -13,6 +14,7 @@ LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
|
|||
| ^^^^^^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error[E0119]: conflicting implementations of trait `MyTrait`:
|
||||
--> $DIR/issue-64494.rs:19:1
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | fact::<{ N - 1 }>();
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | impl <const N: usize> Collatz<{Some(N)}> {}
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
|
||||
--> $DIR/issue-68366.rs:12:13
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | struct Const<const V: [usize; 0]> {}
|
|||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | struct Foo<const V: [usize; 0] > {}
|
|||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
|
|||
| ^^^^^^^^ cannot perform const operation using `INT_BITS`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `INT_BITS`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/issue-68977.rs:29:28
|
||||
|
|
@ -13,6 +14,7 @@ LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
|
|||
| ^^^^^^^^^ cannot perform const operation using `FRAC_BITS`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `FRAC_BITS`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
|
|||
| ^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | Condition<{ LHS <= RHS }>: True
|
|||
| ^^^ cannot perform const operation using `LHS`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `LHS`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/issue-72787.rs:11:24
|
||||
|
|
@ -13,6 +14,7 @@ LL | Condition<{ LHS <= RHS }>: True
|
|||
| ^^^ cannot perform const operation using `RHS`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `RHS`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/issue-72787.rs:26:25
|
||||
|
|
@ -21,6 +23,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
|
|||
| ^ cannot perform const operation using `I`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `I`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/issue-72787.rs:26:36
|
||||
|
|
@ -29,6 +32,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
|
|||
| ^ cannot perform const operation using `J`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `J`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error[E0283]: type annotations needed
|
||||
--> $DIR/issue-72787.rs:22:26
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue,
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | fn hoge<const IN: [u32; LEN]>() {}
|
|||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | fn test<const N: [u8; 1 + 2]>() {}
|
|||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `[u8; _]` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/issue-74101.rs:10:21
|
||||
|
|
@ -14,7 +14,7 @@ LL | struct Foo<const N: [u8; 1 + 2]>;
|
|||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | fn ice_struct_fn<const I: IceEnum>() {}
|
|||
| ^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | struct Outer<const I: Inner>;
|
|||
| ^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `Inner` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/issue-74950.rs:18:23
|
||||
|
|
@ -14,7 +14,7 @@ LL | struct Outer<const I: Inner>;
|
|||
| ^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `Inner` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/issue-74950.rs:18:23
|
||||
|
|
@ -23,7 +23,7 @@ LL | struct Outer<const I: Inner>;
|
|||
| ^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `Inner` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/issue-74950.rs:18:23
|
||||
|
|
@ -32,7 +32,7 @@ LL | struct Outer<const I: Inner>;
|
|||
| ^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `Inner` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/issue-74950.rs:18:23
|
||||
|
|
@ -41,7 +41,7 @@ LL | struct Outer<const I: Inner>;
|
|||
| ^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | struct Foo<const N: [u8; Bar::<u32>::value()]>;
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
|
|||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/issue-76701-ty-param-in-const.rs:12:42
|
||||
|
|
@ -13,6 +14,7 @@ LL | fn const_param<const N: usize>() -> [u8; N + 1] {
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ LL | let _: foo!({{ N }});
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/macro_rules-braces.rs:41:19
|
||||
|
|
@ -35,6 +36,7 @@ LL | let _: bar!({ N });
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/macro_rules-braces.rs:46:20
|
||||
|
|
@ -43,6 +45,7 @@ LL | let _: baz!({{ N }});
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/macro_rules-braces.rs:51:19
|
||||
|
|
@ -51,6 +54,7 @@ LL | let _: biz!({ N });
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | struct Break0<const N: usize>([u8; { N + 1 }]);
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:14:40
|
||||
|
|
@ -13,6 +14,7 @@ LL | struct Break1<const N: usize>([u8; { { N } }]);
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:18:17
|
||||
|
|
@ -21,6 +23,7 @@ LL | let _: [u8; N + 1];
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:23:17
|
||||
|
|
@ -29,6 +32,7 @@ LL | let _ = [0; N + 1];
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:27:45
|
||||
|
|
@ -37,6 +41,7 @@ LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
|
|||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:30:47
|
||||
|
|
@ -45,6 +50,7 @@ LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
|
|||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/complex-expression.rs:34:32
|
||||
|
|
@ -53,6 +59,7 @@ LL | let _: [u8; size_of::<*mut T>() + 1];
|
|||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
warning: cannot use constants which depend on generic parameters in types
|
||||
--> $DIR/complex-expression.rs:39:17
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | struct Foo<const N: [u8; 0]>;
|
|||
| ^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `()` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/complex-types.rs:7:21
|
||||
|
|
@ -14,7 +14,7 @@ LL | struct Bar<const N: ()>;
|
|||
| ^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `No` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/complex-types.rs:12:21
|
||||
|
|
@ -23,7 +23,7 @@ LL | struct Fez<const N: No>;
|
|||
| ^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `&'static u8` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/complex-types.rs:15:21
|
||||
|
|
@ -32,7 +32,7 @@ LL | struct Faz<const N: &'static u8>;
|
|||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `!` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/complex-types.rs:18:21
|
||||
|
|
@ -41,7 +41,7 @@ LL | struct Fiz<const N: !>;
|
|||
| ^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `()` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/complex-types.rs:21:19
|
||||
|
|
@ -50,7 +50,7 @@ LL | enum Goo<const N: ()> { A, B }
|
|||
| ^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `()` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/complex-types.rs:24:20
|
||||
|
|
@ -59,7 +59,7 @@ LL | union Boo<const N: ()> { a: () }
|
|||
| ^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | fn t1() -> [u8; std::mem::size_of::<Self>()];
|
|||
| ^^^^ cannot perform const operation using `Self`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic `Self` types are currently not permitted in anonymous constants
|
||||
--> $DIR/self-ty-in-const-1.rs:14:41
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | fn a<const X: &'static [u32]>() {}
|
|||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | struct Const<const P: &'static ()>;
|
|||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ LL | | }]>;
|
|||
| |__^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
|
||||
--> $DIR/nested-type.rs:16:5
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
|
|||
| ^ cannot perform const operation using `T`
|
||||
|
|
||||
= note: type parameters may not be used in const expressions
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: constant values inside of type parameter defaults must not depend on generic parameters
|
||||
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | struct ConstString<const T: &'static str>;
|
|||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `&'static [u8]` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/slice-const-param-mismatch.rs:10:28
|
||||
|
|
@ -14,7 +14,7 @@ LL | struct ConstBytes<const T: &'static [u8]>;
|
|||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | pub fn function_with_str<const STRING: &'static str>() -> &'static str {
|
|||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `&'static [u8]` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/slice-const-param.rs:13:41
|
||||
|
|
@ -14,7 +14,7 @@ LL | pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] {
|
|||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | struct _Range<const R: std::ops::Range<usize>>;
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `RangeFrom<usize>` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/const-generics-range.rs:13:28
|
||||
|
|
@ -14,7 +14,7 @@ LL | struct _RangeFrom<const R: std::ops::RangeFrom<usize>>;
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `RangeFull` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/const-generics-range.rs:18:28
|
||||
|
|
@ -23,7 +23,7 @@ LL | struct _RangeFull<const R: std::ops::RangeFull>;
|
|||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `RangeInclusive<usize>` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/const-generics-range.rs:24:33
|
||||
|
|
@ -32,7 +32,7 @@ LL | struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>;
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `RangeTo<usize>` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/const-generics-range.rs:29:26
|
||||
|
|
@ -41,7 +41,7 @@ LL | struct _RangeTo<const R: std::ops::RangeTo<usize>>;
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `RangeToInclusive<usize>` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/const-generics-range.rs:34:35
|
||||
|
|
@ -50,7 +50,7 @@ LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>;
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LL | trait Get<'a, const N: &'static str> {
|
|||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: `&'static str` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/issue-71348.rs:19:25
|
||||
|
|
@ -14,7 +14,7 @@ LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Ta
|
|||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= note: more complex types are supported with `#[feature(const_generics)]`
|
||||
= help: more complex types are supported with `#[feature(const_generics)]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ LL | let _: [u8; N + 1];
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: generic parameters may not be used in const operations
|
||||
--> $DIR/wf-misc.rs:17:21
|
||||
|
|
@ -13,6 +14,7 @@ LL | let _: Const::<{N + 1}>;
|
|||
| ^ cannot perform const operation using `N`
|
||||
|
|
||||
= help: const parameters may only be used as standalone arguments, i.e. `N`
|
||||
= help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue