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:
bors 2020-11-24 12:27:30 +00:00
commit 53d19b37c5
92 changed files with 1002 additions and 315 deletions

View file

@ -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();

View file

@ -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));

View file

@ -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
}

View file

@ -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],

View file

@ -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 {

View file

@ -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()
}
};

View file

@ -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()
}

View file

@ -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 }
}
}

View file

@ -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()
}

View file

@ -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 {

View file

@ -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)

View 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
languages 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].
![Screenshot of IDA Pro listing cross references to __rust_probestack in hello-rust.](images/image1.png "Cross references to __rust_probestack in hello-rust.")
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.
![Screenshot of IDA Pro listing cross references to __rust_probestack in modified hello-rust.](images/image2.png "Cross references to __rust_probestack in 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.
Rusts 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 systems 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).
![Screenshot of IDA Pro listing cross references to __stack_chk_fail in hello-rust.](images/image3.png "Cross references to __stack_chk_fail in hello-rust.")
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 Rusts 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>.

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View file

@ -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

View file

@ -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<'_> {

View file

@ -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.

View file

@ -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,

View file

@ -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 {

View file

@ -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");

View file

@ -60,7 +60,7 @@ impl<'a> DocFolder for SourceCollector<'a> {
}
};
}
self.fold_item_recur(item)
Some(self.fold_item_recur(item))
}
}

View file

@ -268,6 +268,6 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
}
}
self.fold_item_recur(i)
Some(self.fold_item_recur(i))
}
}

View file

@ -105,7 +105,7 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
}
}
self.fold_item_recur(item)
Some(self.fold_item_recur(item))
}
}

View file

@ -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))
}
}

View file

@ -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;
}

View file

@ -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))
}
}

View file

@ -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))
}
}

View file

@ -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))
}
}

View file

@ -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))
}
}

View file

@ -39,6 +39,6 @@ impl DocFolder for CfgPropagator {
let result = self.fold_item_recur(item);
self.parent_cfg = old_parent_cfg;
result
Some(result)
}
}

View file

@ -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))
}
}

View file

@ -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)),
}
}
}

View file

@ -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))
}
}

View file

@ -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));
}
}
}

View 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
}

View file

@ -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
|

View file

@ -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()].

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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