# Original downloaded here came from
# http://releases.llvm.org/7.0.0/LLVM-7.0.0-win64.exe
- script: |
- powershell -Command "iwr -outf %TEMP%\LLVM-7.0.0-win64.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/LLVM-7.0.0-win64.exe"
+ powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf %TEMP%\LLVM-7.0.0-win64.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/LLVM-7.0.0-win64.exe"
set CLANG_DIR=%CD%\citools\clang-rust
%TEMP%\LLVM-7.0.0-win64.exe /S /NCRC /D=%CLANG_DIR%
set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --set llvm.clang-cl=%CLANG_DIR%\bin\clang-cl.exe
- script: |
md sccache
- powershell -Command "iwr -outf sccache\sccache.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-26-sccache-x86_64-pc-windows-msvc"
+ powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf sccache\sccache.exe https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2018-04-26-sccache-x86_64-pc-windows-msvc"
echo ##vso[task.prependpath]%CD%\sccache
displayName: Install sccache (Windows)
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
# Note that we don't literally overwrite the gdb.exe binary because it appears
# to just use gdborig.exe, so that's the binary we deal with instead.
- script: |
- powershell -Command "iwr -outf %MINGW_ARCHIVE% %MINGW_URL%/%MINGW_ARCHIVE%"
+ powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf %MINGW_ARCHIVE% %MINGW_URL%/%MINGW_ARCHIVE%"
7z x -y %MINGW_ARCHIVE% > nul
- powershell -Command "iwr -outf 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_URL%/2017-04-20-%MSYS_BITS%bit-gdborig.exe"
+ powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_URL%/2017-04-20-%MSYS_BITS%bit-gdborig.exe"
mv 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_DIR%\bin\gdborig.exe
echo ##vso[task.prependpath]%CD%\%MINGW_DIR%\bin
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['MINGW_URL'],''))
# Note that this is originally from the github releases patch of Ninja
- script: |
md ninja
- powershell -Command "iwr -outf 2017-03-15-ninja-win.zip https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-03-15-ninja-win.zip"
+ powershell -Command "$ProgressPreference = 'SilentlyContinue'; iwr -outf 2017-03-15-ninja-win.zip https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2017-03-15-ninja-win.zip"
7z x -oninja 2017-03-15-ninja-win.zip
del 2017-03-15-ninja-win.zip
set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --enable-ninja
"cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-std-workspace-core 1.0.0",
]
"unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "punycode"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "quick-error"
version = "1.2.2"
[[package]]
name = "rustc-demangle"
-version = "0.1.10"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"compiler_builtins 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_llvm 0.0.0",
]
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
- "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_allocator 0.0.0",
"rustc_apfloat 0.0.0",
"rustc_codegen_utils 0.0.0",
dependencies = [
"flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "punycode 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
+ "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_data_structures 0.0.0",
"rustc_metadata 0.0.0",
"rustc_mir 0.0.0",
"checksum proptest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24f5844db2f839e97e3021980975f6ebf8691d9b9b2ca67ed3feb38dc3edb52c"
"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
"checksum pulldown-cmark 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "051e60ace841b3bfecd402fe5051c06cb3bec4a6e6fdd060a37aa8eb829a1db3"
+"checksum punycode 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6ddd112cca70a4d30883b2d21568a1d376ff8be4758649f64f973c6845128ad3"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum rustc-ap-serialize 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf09c60aaee892b0fd107544cfe607d8d463e7f33da34aa823566b8fd2b17f53"
"checksum rustc-ap-syntax 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "69f38cc120ff317678bbda8c4f58c1bbc1de64b615383ab01480482dde5e95a1"
"checksum rustc-ap-syntax_pos 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20a0a201141c5c416b1924b079eeefc7b013e34ece0740ce4997f358b3684a7f"
-"checksum rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "82ae957aa1b3055d8e086486723c0ccd3d7b8fa190ae8fa2e35543b6171c810e"
+"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
"checksum rustc-rayon 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d98c51d9cbbe810c8b6693236d3412d8cd60513ff27a3e1b6af483dca0af544"
"checksum rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2e07e19601f21c59aad953c2632172ba70cb27e685771514ea66e4062b3363"
book!(
EditionGuide, "src/doc/edition-guide", "edition-guide", RustbookVersion::MdBook2;
EmbeddedBook, "src/doc/embedded-book", "embedded-book", RustbookVersion::MdBook2;
- Nomicon, "src/doc/nomicon", "nomicon", RustbookVersion::MdBook1;
+ Nomicon, "src/doc/nomicon", "nomicon", RustbookVersion::MdBook2;
Reference, "src/doc/reference", "reference", RustbookVersion::MdBook1;
RustByExample, "src/doc/rust-by-example", "rust-by-example", RustbookVersion::MdBook1;
RustcBook, "src/doc/rustc", "rustc", RustbookVersion::MdBook1;
- RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::MdBook1;
+ RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::MdBook2;
);
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
target: self.target,
name: INTERNER.intern_str("unstable-book"),
src: builder.md_doc_out(self.target),
- version: RustbookVersion::MdBook1,
+ version: RustbookVersion::MdBook2,
})
}
}
#
# Versions of the toolchain components are configurable in `musl-cross-make/Makefile` and
# musl unlike GLIBC is forward compatible so upgrading it shouldn't break old distributions.
-# Right now we have: Binutils 2.27, GCC 6.3.0, musl 1.1.18
+# Right now we have: Binutils 2.27, GCC 6.4.0, musl 1.1.22.
set -ex
hide_output() {
# Apparently applying `-fPIC` everywhere allows them to link successfully.
export CFLAGS="-fPIC $CFLAGS"
-git clone https://github.com/richfelker/musl-cross-make -b v0.9.7
+git clone https://github.com/richfelker/musl-cross-make -b v0.9.8
cd musl-cross-make
hide_output make -j$(nproc) TARGET=$TARGET
An argument of "list" will print a list of possible "rustdoc passes", and other
arguments will be the name of which passes to run in addition to the defaults.
-For more details on passes, see [the chapter on them](passes.html).
+For more details on passes, see [the chapter on them](passes.md).
See also `--no-defaults`.
removes those defaults, allowing you to use `--passes` to specify
exactly which passes you want.
-For more details on passes, see [the chapter on them](passes.html).
+For more details on passes, see [the chapter on them](passes.md).
See also `--passes`.
```
This flag will run your code examples as tests. For more, see [the chapter
-on documentation tests](documentation-tests.html).
+on documentation tests](documentation-tests.md).
See also `--test-args`.
```
This flag will pass options to the test runner when running documentation tests.
-For more, see [the chapter on documentation tests](documentation-tests.html).
+For more, see [the chapter on documentation tests](documentation-tests.md).
See also `--test`.
In addition to the passes below, check out the docs for these flags:
-* [`--passes`](command-line-arguments.html#a--passes-add-more-rustdoc-passes)
-* [`--no-defaults`](command-line-arguments.html#a--no-defaults-dont-run-default-passes)
+* [`--passes`](command-line-arguments.md#--passes-add-more-rustdoc-passes)
+* [`--no-defaults`](command-line-arguments.md#--no-defaults-dont-run-default-passes)
## Default passes
[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions
If you need more power and don't mind losing some of the niceties of
-`asm!`, check out [global_asm](language-features/global-asm.html).
+`asm!`, check out [global_asm](global-asm.md).
[#29641]: https://github.com/rust-lang/rust/issues/29641
-See also [`box_syntax`](language-features/box-syntax.html)
+See also [`box_syntax`](box-syntax.md)
------------------------
[#49733]: https://github.com/rust-lang/rust/issues/49733
-See also [`box_patterns`](language-features/box-patterns.html)
+See also [`box_patterns`](box-patterns.md)
------------------------
If you don't need quite as much power and flexibility as
`global_asm!` provides, and you don't mind restricting your inline
assembly to `fn` bodies only, you might try the
-[asm](language-features/asm.html) feature instead.
+[asm](asm.md) feature instead.
also requires enabling the library feature `compiler_builtins_lib`. You can read
more about this [here][compiler-builtins-lib].
-[compiler-builtins-lib]: library-features/compiler-builtins-lib.html
+[compiler-builtins-lib]: ../library-features/compiler-builtins-lib.md
## More about the language items
[`XID_start`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Start%3A%5D&abb=on&g=&i=
[`XID_continue`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Continue%3A%5D&abb=on&g=&i=
-[strict keywords]: ../reference/keywords.html#strict-keywords
+[strict keywords]: ../../reference/keywords.md#strict-keywords
[`plugin`] and `rustc_private` features as well. For more details, see
their docs.
-[`plugin`]: language-features/plugin.html
+[`plugin`]: plugin.md
------------------------
This feature is part of "compiler plugins." It will often be used with the
[`plugin_registrar`] and `rustc_private` features.
-[`plugin_registrar`]: language-features/plugin-registrar.html
+[`plugin_registrar`]: plugin-registrar.md
------------------------
Plugins can extend Rust's syntax in various ways. One kind of syntax extension
is the procedural macro. These are invoked the same way as [ordinary
-macros](../book/macros.html), but the expansion is performed by arbitrary Rust
+macros](../../book/macros.md), but the expansion is performed by arbitrary Rust
code that manipulates syntax trees at
compile time.
a way to define new literal syntax for any data type.
In addition to procedural macros, you can define new
-[`derive`](../reference/attributes/derive.html)-like attributes and other kinds
+[`derive`](../../reference/attributes/derive.md)-like attributes and other kinds
of extensions. See `Registry::register_syntax_extension` and the
`SyntaxExtension` enum. For a more involved macro example, see
[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
# Lint plugins
Plugins can extend [Rust's lint
-infrastructure](../reference/attributes/diagnostics.html#lint-check-attributes) with
+infrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with
additional checks for code style, safety, etc. Now let's write a plugin
[`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/lint_plugin_test.rs)
that warns about any item named `lintme`.
to access type information.
Lints defined by plugins are controlled by the usual [attributes and compiler
-flags](../reference/attributes/diagnostics.html#lint-check-attributes), e.g.
+flags](../../reference/attributes/diagnostics.md#lint-check-attributes), e.g.
`#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the
first argument to `declare_lint!`, with appropriate case and punctuation
conversion.
The tracking issue for this feature is [#29625]
-See Also: [`fn_traits`](library-features/fn-traits.html)
+See Also: [`fn_traits`](../library-features/fn-traits.md)
[#29625]: https://github.com/rust-lang/rust/issues/29625
The tracking issue for this feature is [#29625]
-See Also: [`unboxed_closures`](language-features/unboxed-closures.html)
+See Also: [`unboxed_closures`](../language-features/unboxed-closures.md)
[#29625]: https://github.com/rust-lang/rust/issues/29625
Before the introduction of [`unsized_locals`][unsized_locals], we had been unable to provide the former impls. That means, unlike `&dyn Fn()` or `&mut dyn FnMut()` we could not use `Box<dyn FnOnce()>` at that time.
-[unsized_locals]: language-features/unsized-locals.html
+[unsized_locals]: ../language-features/unsized-locals.md
`FnBox()` is an alternative approach to `Box<dyn FnBox()>` is delegated to `FnBox::call_box` which doesn't need unsized locals. As we now have `Box<dyn FnOnce()>` working, the `fnbox` feature is going to be removed.
The `box_syntax` feature [has a chapter][box] describing how to use it.
-[box]: language-features/box-syntax.html
+[box]: language-features/box-syntax.md
Because this documentation relates to unstable features, we make no guarantees
that what is contained here is accurate or up to date. It's developed on a
#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_array)]
#![feature(alloc_layout_extra)]
#![feature(try_trait)]
-#![feature(iter_nth_back)]
// Allow testing this library
///
/// Using `AsMut` as trait bound for a generic function we can accept all mutable references
/// that can be converted to type `&mut T`. Because [`Box<T>`] implements `AsMut<T>` we can
-/// write a function `add_one`that takes all arguments that can be converted to `&mut u64`.
-/// Because [`Box<T>`] implements `AsMut<T>` `add_one` accepts arguments of type
+/// write a function `add_one` that takes all arguments that can be converted to `&mut u64`.
+/// Because [`Box<T>`] implements `AsMut<T>`, `add_one` accepts arguments of type
/// `&mut Box<u64>` as well:
///
/// ```
/// Basic usage:
///
/// ```
- /// #![feature(iter_nth_back)]
/// let a = [1, 2, 3];
/// assert_eq!(a.iter().nth_back(2), Some(&1));
/// ```
/// Calling `nth_back()` multiple times doesn't rewind the iterator:
///
/// ```
- /// #![feature(iter_nth_back)]
/// let a = [1, 2, 3];
///
/// let mut iter = a.iter();
/// Returning `None` if there are less than `n + 1` elements:
///
/// ```
- /// #![feature(iter_nth_back)]
/// let a = [1, 2, 3];
/// assert_eq!(a.iter().nth_back(10), None);
/// ```
#[inline]
- #[unstable(feature = "iter_nth_back", issue = "56995")]
+ #[stable(feature = "iter_nth_back", since = "1.37.0")]
fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
for x in self.rev() {
if n == 0 { return Some(x) }
#![feature(const_str_len)]
#![feature(const_int_conversion)]
#![feature(const_transmute)]
-#![feature(reverse_bits)]
#![feature(non_exhaustive)]
#![feature(structural_match)]
#![feature(abi_unadjusted)]
Basic usage:
```
-#![feature(reverse_bits)]
-
let n = ", $swap_op, stringify!($SelfT), ";
let m = n.reverse_bits();
assert_eq!(m, ", $reversed, ");
```"),
- #[unstable(feature = "reverse_bits", issue = "48763")]
- #[rustc_const_unstable(feature = "const_int_conversion")]
+ #[stable(feature = "reverse_bits", since = "1.37.0")]
#[inline]
#[must_use]
pub const fn reverse_bits(self) -> Self {
Basic usage:
```
-#![feature(reverse_bits)]
-
let n = ", $swap_op, stringify!($SelfT), ";
let m = n.reverse_bits();
assert_eq!(m, ", $reversed, ");
```"),
- #[unstable(feature = "reverse_bits", issue = "48763")]
+ #[stable(feature = "reverse_bits", since = "1.37.0")]
#[inline]
#[must_use]
pub const fn reverse_bits(self) -> Self {
/// Basic usage:
///
/// ```
- /// #![feature(reverse_bits)]
/// use std::num::Wrapping;
///
/// let n = Wrapping(0b0000000_01010101i16);
/// assert_eq!(m.0 as u16, 0b10101010_00000000);
/// assert_eq!(m, Wrapping(-22016));
/// ```
- #[unstable(feature = "reverse_bits", issue = "48763")]
+ #[stable(feature = "reverse_bits", since = "1.37.0")]
#[inline]
#[must_use]
pub const fn reverse_bits(self) -> Self {
/// * Values of type `&T` are coerced to values of type `&U`
/// * `T` implicitly implements all the (immutable) methods of the type `U`.
///
-/// For more details, visit [the chapter in *The Rust Programming Language*]
-/// [book] as well as the reference sections on [the dereference operator]
-/// [ref-deref-op], [method resolution] and [type coercions].
+/// For more details, visit [the chapter in *The Rust Programming Language*][book]
+/// as well as the reference sections on [the dereference operator][ref-deref-op],
+/// [method resolution] and [type coercions].
///
/// [book]: ../../book/ch15-02-deref.html
/// [`DerefMut`]: trait.DerefMut.html
/// * Values of type `&mut T` are coerced to values of type `&mut U`
/// * `T` implicitly implements all the (mutable) methods of the type `U`.
///
-/// For more details, visit [the chapter in *The Rust Programming Language*]
-/// [book] as well as the reference sections on [the dereference operator]
-/// [ref-deref-op], [method resolution] and [type coercions].
+/// For more details, visit [the chapter in *The Rust Programming Language*][book]
+/// as well as the reference sections on [the dereference operator][ref-deref-op],
+/// [method resolution] and [type coercions].
///
/// [book]: ../../book/ch15-02-deref.html
/// [`Deref`]: trait.Deref.html
#![feature(fmt_internals)]
#![feature(hashmap_internals)]
#![feature(is_sorted)]
-#![feature(iter_nth_back)]
#![feature(iter_once_with)]
#![feature(pattern)]
#![feature(range_is_empty)]
#![feature(test)]
#![feature(trusted_len)]
#![feature(try_trait)]
-#![feature(reverse_bits)]
#![feature(inner_deref)]
#![feature(slice_internals)]
#![feature(slice_partition_dedup)]
ty::ReClosureBound(vid) => {
vid.hash_stable(hcx, hasher);
}
- ty::ReLateBound(..) |
ty::ReVar(..) |
ty::RePlaceholder(..) => {
bug!("StableHasher: unexpected region {:?}", *self)
format!("the anonymous lifetime #{} defined on", idx + 1),
self.hir().span_by_hir_id(node),
),
- ty::BrFresh(_) => (
- "an anonymous lifetime defined on".to_owned(),
- self.hir().span_by_hir_id(node),
- ),
_ => (
format!("the lifetime {} as defined on", region),
cm.def_span(self.hir().span_by_hir_id(node)),
use rustc_data_structures::unify as ut;
use crate::ty::ReStatic;
use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::{BrFresh, ReLateBound, ReVar};
+use crate::ty::{ReLateBound, ReVar};
use crate::ty::{Region, RegionVid};
use std::collections::BTreeMap;
-use std::{cmp, fmt, mem, u32};
+use std::{cmp, fmt, mem};
use std::ops::Range;
mod leak_check;
/// exist). This prevents us from making many such regions.
glbs: CombineMap<'tcx>,
- /// Global counter used during the GLB algorithm to create unique
- /// names for fresh bound regions
- bound_count: u32,
-
/// The undo log records actions that might later be undone.
///
/// Note: `num_open_snapshots` is used to track if we are actively
data,
lubs,
glbs,
- bound_count: _,
undo_log: _,
num_open_snapshots: _,
unification_table,
}
}
- pub fn new_bound(
- &mut self,
- tcx: TyCtxt<'_, '_, 'tcx>,
- debruijn: ty::DebruijnIndex,
- ) -> Region<'tcx> {
- // Creates a fresh bound variable for use in GLB computations.
- // See discussion of GLB computation in the large comment at
- // the top of this file for more details.
- //
- // This computation is potentially wrong in the face of
- // rollover. It's conceivable, if unlikely, that one might
- // wind up with accidental capture for nested functions in
- // that case, if the outer function had bound regions created
- // a very long time before and the inner function somehow
- // wound up rolling over such that supposedly fresh
- // identifiers were in fact shadowed. For now, we just assert
- // that there is no rollover -- eventually we should try to be
- // robust against this possibility, either by checking the set
- // of bound identifiers that appear in a given expression and
- // ensure that we generate one that is distinct, or by
- // changing the representation of bound regions in a fn
- // declaration
-
- let sc = self.bound_count;
- self.bound_count = sc + 1;
-
- if sc >= self.bound_count {
- bug!("rollover in RegionInference new_bound()");
- }
-
- tcx.mk_region(ReLateBound(debruijn, BrFresh(sc)))
- }
-
fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
// cannot add constraints once regions are resolved
debug!(
use rustc_data_structures::sorted_map::SortedMap;
use rustc_macros::HashStable;
use rustc_target::abi::HasDataLayout;
+use std::borrow::Cow;
/// Used by `check_bounds` to indicate whether the pointer needs to be just inbounds
/// or also inbounds of a *live* allocation.
impl<Tag, Extra> Allocation<Tag, Extra> {
/// Creates a read-only allocation initialized by the given bytes
- pub fn from_bytes(slice: &[u8], align: Align, extra: Extra) -> Self {
- let undef_mask = UndefMask::new(Size::from_bytes(slice.len() as u64), true);
+ pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align, extra: Extra) -> Self {
+ let bytes = slice.into().into_owned();
+ let undef_mask = UndefMask::new(Size::from_bytes(bytes.len() as u64), true);
Self {
- bytes: slice.to_owned(),
+ bytes,
relocations: Relocations::new(),
undef_mask,
align,
}
}
- pub fn from_byte_aligned_bytes(slice: &[u8], extra: Extra) -> Self {
+ pub fn from_byte_aligned_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, extra: Extra) -> Self {
Allocation::from_bytes(slice, Align::from_bytes(1).unwrap(), extra)
}
fatal_cycle
desc { "test whether a crate has #![no_builtins]" }
}
+ query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion {
+ fatal_cycle
+ desc { "query a crate's symbol mangling version" }
+ }
query extern_crate(_: DefId) -> Option<&'tcx ExternCrate> {
eval_always
}
}
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+pub enum SymbolManglingVersion {
+ Legacy,
+ V0,
+}
+
+impl_stable_hash_via_hash!(SymbolManglingVersion);
+
#[derive(Clone, Copy, PartialEq, Hash)]
pub enum DebugInfo {
None,
Some("an optional path to the profiling data output directory");
pub const parse_merge_functions: Option<&str> =
Some("one of: `disabled`, `trampolines`, or `aliases`");
+ pub const parse_symbol_mangling_version: Option<&str> =
+ Some("either `legacy` or `v0` (RFC 2603)");
}
#[allow(dead_code)]
mod $mod_set {
- use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath};
+ use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
+ SymbolManglingVersion};
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
use std::path::PathBuf;
use std::str::FromStr;
}
true
}
+
+ fn parse_symbol_mangling_version(
+ slot: &mut SymbolManglingVersion,
+ v: Option<&str>,
+ ) -> bool {
+ *slot = match v {
+ Some("legacy") => SymbolManglingVersion::Legacy,
+ Some("v0") => SymbolManglingVersion::V0,
+ _ => return false,
+ };
+ true
+ }
}
) }
"only allow the listed language features to be enabled in code (space separated)"),
emit_artifact_notifications: bool = (false, parse_bool, [UNTRACKED],
"emit notifications after each artifact has been output (only in the JSON format)"),
+ symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
+ parse_symbol_mangling_version, [TRACKED],
+ "which mangling version to use for symbol names"),
}
pub fn default_lib_output() -> CrateType {
use std::path::PathBuf;
use std::collections::hash_map::DefaultHasher;
use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
- Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath};
+ Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
+ SymbolManglingVersion};
use syntax::feature_gate::UnstableFeatures;
use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
use syntax::edition::Edition;
impl_dep_tracking_hash_via_hash!(Edition);
impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
+ impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
impl_dep_tracking_hash_for_sortable_vec_of!(String);
impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
use std::path::PathBuf;
- use super::{Externs, OutputType, OutputTypes};
+ use super::{Externs, OutputType, OutputTypes, SymbolManglingVersion};
use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel};
use syntax::symbol::sym;
use syntax::edition::{Edition, DEFAULT_EDITION};
opts = reference.clone();
opts.debugging_opts.allow_features = Some(vec![String::from("lang_items")]);
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
}
#[test]
br
}
ty::BrAnon(_) |
- ty::BrFresh(_) |
ty::BrEnv => {
let name = loop {
let name = name_by_region_index(region_index);
use crate::mir;
use crate::mir::interpret::GlobalId;
use crate::session::CrateDisambiguator;
-use crate::session::config::{EntryFnType, OutputFilenames, OptLevel};
+use crate::session::config::{EntryFnType, OutputFilenames, OptLevel, SymbolManglingVersion};
use crate::traits::{self, Vtable};
use crate::traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal,
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
- ty::BrFresh(n) => write!(f, "BrFresh({:?})", n),
ty::BrNamed(did, name) => {
write!(f, "BrNamed({:?}:{:?}, {})",
did.krate, did.index, name)
/// the event of shadowing.
BrNamed(DefId, InternedString),
- /// Fresh bound identifiers created during GLB computations.
- BrFresh(u32),
-
/// Anonymous region for the implicit env pointer parameter
/// to a closure
BrEnv,
[dependencies]
cc = "1.0.1" # Used to locate MSVC
num_cpus = "1.0"
-rustc-demangle = "0.1.4"
+rustc-demangle = "0.1.15"
rustc_llvm = { path = "../librustc_llvm" }
memmap = "0.6"
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc::hir;
use syntax::ast::{self, FloatTy};
-use syntax::symbol::LocalInternedString;
use rustc_codegen_ssa::traits::*;
}
"type_name" => {
let tp_ty = substs.type_at(0);
- let ty_name = LocalInternedString::intern(&tp_ty.to_string());
- self.const_str_slice(ty_name)
+ let ty_name = rustc_mir::interpret::type_name(self.tcx, tp_ty);
+ OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self)
}
"type_id" => {
self.const_u64(self.tcx.type_id_hash(substs.type_at(0)))
bitflags = "1.0.4"
cc = "1.0.1"
num_cpus = "1.0"
-rustc-demangle = "0.1.4"
+rustc-demangle = "0.1.15"
memmap = "0.6"
log = "0.4.5"
libc = "0.2.44"
@irinagpopa started to parametrize the types of `rustc_codegen_llvm` by a generic `Value` type, implemented in LLVM by a reference `&'ll Value`. This work has been extended to all structures inside the `mir` folder and elsewhere, as well as for LLVM's `BasicBlock` and `Type` types.
-The two most important structures for the LLVM codegen are `CodegenCx` and `Builder`. They are parametrized by multiple liftime parameters and the type for `Value`.
+The two most important structures for the LLVM codegen are `CodegenCx` and `Builder`. They are parametrized by multiple lifetime parameters and the type for `Value`.
```rust
struct CodegenCx<'ll, 'tcx: 'll> {
pub fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
val: &'tcx ty::Const<'tcx>
- ) -> Result<Self, ErrorHandled> {
+ ) -> Self {
let layout = bx.layout_of(val.ty);
if layout.is_zst() {
- return Ok(OperandRef::new_zst(bx, layout));
+ return OperandRef::new_zst(bx, layout);
}
let val = match val.val {
OperandValue::Pair(a_llval, b_llval)
},
ConstValue::ByRef(ptr, alloc) => {
- return Ok(bx.load_operand(bx.from_const_alloc(layout, alloc, ptr.offset)));
+ return bx.load_operand(bx.from_const_alloc(layout, alloc, ptr.offset));
},
};
- Ok(OperandRef {
+ OperandRef {
val,
layout
- })
+ }
}
/// Asserts that this operand refers to a scalar and returns
mir::Operand::Constant(ref constant) => {
let ty = self.monomorphize(&constant.ty);
self.eval_mir_constant(constant)
- .and_then(|c| OperandRef::from_const(bx, c))
+ .map(|c| OperandRef::from_const(bx, c))
.unwrap_or_else(|err| {
match err {
// errored or at least linted
[dependencies]
flate2 = "1.0"
log = "0.4"
+punycode = "0.4.0"
+rustc-demangle = "0.1.15"
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(core_intrinsics)]
#![feature(custom_attribute)]
+#![feature(never_type)]
#![feature(nll)]
#![allow(unused_attributes)]
#![feature(rustc_diagnostic_macros)]
//! virtually impossible. Thus, symbol hash generation exclusively relies on
//! DefPaths which are much more robust in the face of changes to the code base.
-use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc::hir::def_id::LOCAL_CRATE;
use rustc::hir::Node;
use rustc::hir::CodegenFnAttrFlags;
-use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
-use rustc::ich::NodeIdHashingMode;
-use rustc::ty::print::{PrettyPrinter, Printer, Print};
+use rustc::session::config::SymbolManglingVersion;
use rustc::ty::query::Providers;
-use rustc::ty::subst::{Kind, SubstsRef, UnpackedKind};
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::mir::interpret::{ConstValue, Scalar};
-use rustc::util::common::record_time;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc::ty::{self, TyCtxt};
use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt};
use rustc_mir::monomorphize::Instance;
use log::debug;
-use std::fmt::{self, Write};
-use std::mem::{self, discriminant};
+mod legacy;
+mod v0;
pub fn provide(providers: &mut Providers<'_>) {
*providers = Providers {
- symbol_name,
+ symbol_name: |tcx, instance| ty::SymbolName {
+ name: symbol_name(tcx, instance),
+ },
..*providers
};
}
-fn get_symbol_hash<'a, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
-
- // the DefId of the item this name is for
- def_id: DefId,
-
- // instance this name will be for
- instance: Instance<'tcx>,
-
- // type of the item, without any generic
- // parameters substituted; this is
- // included in the hash as a kind of
- // safeguard.
- item_type: Ty<'tcx>,
-
- // values for generic type parameters,
- // if any.
- substs: SubstsRef<'tcx>,
-) -> u64 {
- debug!(
- "get_symbol_hash(def_id={:?}, parameters={:?})",
- def_id, substs
- );
-
- let mut hasher = StableHasher::<u64>::new();
- let mut hcx = tcx.create_stable_hashing_context();
-
- record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
- // the main symbol name is not necessarily unique; hash in the
- // compiler's internal def-path, guaranteeing each symbol has a
- // truly unique path
- tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
-
- // Include the main item-type. Note that, in this case, the
- // assertions about `needs_subst` may not hold, but this item-type
- // ought to be the same for every reference anyway.
- assert!(!item_type.has_erasable_regions());
- hcx.while_hashing_spans(false, |hcx| {
- hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
- item_type.hash_stable(hcx, &mut hasher);
- });
- });
-
- // If this is a function, we hash the signature as well.
- // This is not *strictly* needed, but it may help in some
- // situations, see the `run-make/a-b-a-linker-guard` test.
- if let ty::FnDef(..) = item_type.sty {
- item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher);
- }
-
- // also include any type parameters (for generic items)
- assert!(!substs.has_erasable_regions());
- assert!(!substs.needs_subst());
- substs.hash_stable(&mut hcx, &mut hasher);
-
- let is_generic = substs.non_erasable_generics().next().is_some();
- let avoid_cross_crate_conflicts =
- // If this is an instance of a generic function, we also hash in
- // the ID of the instantiating crate. This avoids symbol conflicts
- // in case the same instances is emitted in two crates of the same
- // project.
- is_generic ||
-
- // If we're dealing with an instance of a function that's inlined from
- // another crate but we're marking it as globally shared to our
- // compliation (aka we're not making an internal copy in each of our
- // codegen units) then this symbol may become an exported (but hidden
- // visibility) symbol. This means that multiple crates may do the same
- // and we want to be sure to avoid any symbol conflicts here.
- match MonoItem::Fn(instance).instantiation_mode(tcx) {
- InstantiationMode::GloballyShared { may_conflict: true } => true,
- _ => false,
- };
-
- if avoid_cross_crate_conflicts {
- let instantiating_crate = if is_generic {
- if !def_id.is_local() && tcx.sess.opts.share_generics() {
- // If we are re-using a monomorphization from another crate,
- // we have to compute the symbol hash accordingly.
- let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id);
-
- upstream_monomorphizations
- .and_then(|monos| monos.get(&substs).cloned())
- .unwrap_or(LOCAL_CRATE)
- } else {
- LOCAL_CRATE
- }
- } else {
- LOCAL_CRATE
- };
-
- (&tcx.original_crate_name(instantiating_crate).as_str()[..])
- .hash_stable(&mut hcx, &mut hasher);
- (&tcx.crate_disambiguator(instantiating_crate)).hash_stable(&mut hcx, &mut hasher);
- }
-
- // We want to avoid accidental collision between different types of instances.
- // Especially, VtableShim may overlap with its original instance without this.
- discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher);
- });
-
- // 64 bits should be enough to avoid collisions.
- hasher.finish()
-}
-
-fn symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> ty::SymbolName {
- ty::SymbolName {
- name: compute_symbol_name(tcx, instance),
- }
-}
-
-fn compute_symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> InternedString {
+fn symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> InternedString {
let def_id = instance.def_id();
let substs = instance.substs;
return tcx.item_name(def_id).as_interned_str();
}
- // We want to compute the "type" of this item. Unfortunately, some
- // kinds of items (e.g., closures) don't have an entry in the
- // item-type array. So walk back up the find the closest parent
- // that DOES have an entry.
- let mut ty_def_id = def_id;
- let instance_ty;
- loop {
- let key = tcx.def_key(ty_def_id);
- match key.disambiguated_data.data {
- DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => {
- instance_ty = tcx.type_of(ty_def_id);
- break;
- }
- _ => {
- // if we're making a symbol for something, there ought
- // to be a value or type-def or something in there
- // *somewhere*
- ty_def_id.index = key.parent.unwrap_or_else(|| {
- bug!(
- "finding type for {:?}, encountered def-id {:?} with no \
- parent",
- def_id,
- ty_def_id
- );
- });
- }
- }
- }
- // Erase regions because they may not be deterministic when hashed
- // and should not matter anyhow.
- let instance_ty = tcx.erase_regions(&instance_ty);
+ let is_generic = substs.non_erasable_generics().next().is_some();
+ let avoid_cross_crate_conflicts =
+ // If this is an instance of a generic function, we also hash in
+ // the ID of the instantiating crate. This avoids symbol conflicts
+ // in case the same instances is emitted in two crates of the same
+ // project.
+ is_generic ||
- let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs);
-
- let mut printer = SymbolPrinter {
- tcx,
- path: SymbolPath::new(),
- keep_within_component: false,
- }.print_def_path(def_id, &[]).unwrap();
-
- if instance.is_vtable_shim() {
- let _ = printer.write_str("{{vtable-shim}}");
- }
-
- InternedString::intern(&printer.path.finish(hash))
-}
-
-// Follow C++ namespace-mangling style, see
-// http://en.wikipedia.org/wiki/Name_mangling for more info.
-//
-// It turns out that on macOS you can actually have arbitrary symbols in
-// function names (at least when given to LLVM), but this is not possible
-// when using unix's linker. Perhaps one day when we just use a linker from LLVM
-// we won't need to do this name mangling. The problem with name mangling is
-// that it seriously limits the available characters. For example we can't
-// have things like &T in symbol names when one would theoretically
-// want them for things like impls of traits on that type.
-//
-// To be able to work on all platforms and get *some* reasonable output, we
-// use C++ name-mangling.
-#[derive(Debug)]
-struct SymbolPath {
- result: String,
- temp_buf: String,
-}
-
-impl SymbolPath {
- fn new() -> Self {
- let mut result = SymbolPath {
- result: String::with_capacity(64),
- temp_buf: String::with_capacity(16),
+ // If we're dealing with an instance of a function that's inlined from
+ // another crate but we're marking it as globally shared to our
+ // compliation (aka we're not making an internal copy in each of our
+ // codegen units) then this symbol may become an exported (but hidden
+ // visibility) symbol. This means that multiple crates may do the same
+ // and we want to be sure to avoid any symbol conflicts here.
+ match MonoItem::Fn(instance).instantiation_mode(tcx) {
+ InstantiationMode::GloballyShared { may_conflict: true } => true,
+ _ => false,
};
- result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
- result
- }
-
- fn finalize_pending_component(&mut self) {
- if !self.temp_buf.is_empty() {
- let _ = write!(self.result, "{}{}", self.temp_buf.len(), self.temp_buf);
- self.temp_buf.clear();
- }
- }
-
- fn finish(mut self, hash: u64) -> String {
- self.finalize_pending_component();
- // E = end name-sequence
- let _ = write!(self.result, "17h{:016x}E", hash);
- self.result
- }
-}
-
-struct SymbolPrinter<'a, 'tcx> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- path: SymbolPath,
-
- // When `true`, `finalize_pending_component` isn't used.
- // This is needed when recursing into `path_qualified`,
- // or `path_generic_args`, as any nested paths are
- // logically within one component.
- keep_within_component: bool,
-}
-
-// HACK(eddyb) this relies on using the `fmt` interface to get
-// `PrettyPrinter` aka pretty printing of e.g. types in paths,
-// symbol names should have their own printing machinery.
-
-impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
- type Error = fmt::Error;
-
- type Path = Self;
- type Region = Self;
- type Type = Self;
- type DynExistential = Self;
- type Const = Self;
-
- fn tcx(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
- self.tcx
- }
-
- fn print_region(
- self,
- _region: ty::Region<'_>,
- ) -> Result<Self::Region, Self::Error> {
- Ok(self)
- }
-
- fn print_type(
- self,
- ty: Ty<'tcx>,
- ) -> Result<Self::Type, Self::Error> {
- match ty.sty {
- // Print all nominal types as paths (unlike `pretty_print_type`).
- ty::FnDef(def_id, substs) |
- ty::Opaque(def_id, substs) |
- ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) |
- ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) |
- ty::Closure(def_id, ty::ClosureSubsts { substs }) |
- ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => {
- self.print_def_path(def_id, substs)
- }
- _ => self.pretty_print_type(ty),
- }
- }
-
- fn print_dyn_existential(
- mut self,
- predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
- ) -> Result<Self::DynExistential, Self::Error> {
- let mut first = false;
- for p in predicates {
- if !first {
- write!(self, "+")?;
- }
- first = false;
- self = p.print(self)?;
- }
- Ok(self)
- }
- fn print_const(
- mut self,
- ct: &'tcx ty::Const<'tcx>,
- ) -> Result<Self::Const, Self::Error> {
- // only print integers
- if let ConstValue::Scalar(Scalar::Raw { .. }) = ct.val {
- if ct.ty.is_integral() {
- return self.pretty_print_const(ct);
- }
- }
- self.write_str("_")?;
- Ok(self)
- }
-
- fn path_crate(
- mut self,
- cnum: CrateNum,
- ) -> Result<Self::Path, Self::Error> {
- self.write_str(&self.tcx.original_crate_name(cnum).as_str())?;
- Ok(self)
- }
- fn path_qualified(
- self,
- self_ty: Ty<'tcx>,
- trait_ref: Option<ty::TraitRef<'tcx>>,
- ) -> Result<Self::Path, Self::Error> {
- // Similar to `pretty_path_qualified`, but for the other
- // types that are printed as paths (see `print_type` above).
- match self_ty.sty {
- ty::FnDef(..) |
- ty::Opaque(..) |
- ty::Projection(_) |
- ty::UnnormalizedProjection(_) |
- ty::Closure(..) |
- ty::Generator(..)
- if trait_ref.is_none() =>
- {
- self.print_type(self_ty)
- }
-
- _ => self.pretty_path_qualified(self_ty, trait_ref)
- }
- }
+ let instantiating_crate = if avoid_cross_crate_conflicts {
+ Some(if is_generic {
+ if !def_id.is_local() && tcx.sess.opts.share_generics() {
+ // If we are re-using a monomorphization from another crate,
+ // we have to compute the symbol hash accordingly.
+ let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id);
- fn path_append_impl(
- self,
- print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
- _disambiguated_data: &DisambiguatedDefPathData,
- self_ty: Ty<'tcx>,
- trait_ref: Option<ty::TraitRef<'tcx>>,
- ) -> Result<Self::Path, Self::Error> {
- self.pretty_path_append_impl(
- |mut cx| {
- cx = print_prefix(cx)?;
-
- if cx.keep_within_component {
- // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it.
- cx.write_str("::")?;
- } else {
- cx.path.finalize_pending_component();
- }
-
- Ok(cx)
- },
- self_ty,
- trait_ref,
- )
- }
- fn path_append(
- mut self,
- print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
- disambiguated_data: &DisambiguatedDefPathData,
- ) -> Result<Self::Path, Self::Error> {
- self = print_prefix(self)?;
-
- // Skip `::{{constructor}}` on tuple/unit structs.
- match disambiguated_data.data {
- DefPathData::Ctor => return Ok(self),
- _ => {}
- }
-
- if self.keep_within_component {
- // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it.
- self.write_str("::")?;
- } else {
- self.path.finalize_pending_component();
- }
-
- self.write_str(&disambiguated_data.data.as_interned_str().as_str())?;
- Ok(self)
- }
- fn path_generic_args(
- mut self,
- print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
- args: &[Kind<'tcx>],
- ) -> Result<Self::Path, Self::Error> {
- self = print_prefix(self)?;
-
- let args = args.iter().cloned().filter(|arg| {
- match arg.unpack() {
- UnpackedKind::Lifetime(_) => false,
- _ => true,
+ upstream_monomorphizations
+ .and_then(|monos| monos.get(&substs).cloned())
+ .unwrap_or(LOCAL_CRATE)
+ } else {
+ LOCAL_CRATE
}
- });
-
- if args.clone().next().is_some() {
- self.generic_delimiters(|cx| cx.comma_sep(args))
} else {
- Ok(self)
- }
- }
-}
-
-impl PrettyPrinter<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
- fn region_should_not_be_omitted(
- &self,
- _region: ty::Region<'_>,
- ) -> bool {
- false
- }
- fn comma_sep<T>(
- mut self,
- mut elems: impl Iterator<Item = T>,
- ) -> Result<Self, Self::Error>
- where T: Print<'tcx, 'tcx, Self, Output = Self, Error = Self::Error>
- {
- if let Some(first) = elems.next() {
- self = first.print(self)?;
- for elem in elems {
- self.write_str(",")?;
- self = elem.print(self)?;
- }
- }
- Ok(self)
- }
-
- fn generic_delimiters(
- mut self,
- f: impl FnOnce(Self) -> Result<Self, Self::Error>,
- ) -> Result<Self, Self::Error> {
- write!(self, "<")?;
-
- let kept_within_component =
- mem::replace(&mut self.keep_within_component, true);
- self = f(self)?;
- self.keep_within_component = kept_within_component;
-
- write!(self, ">")?;
-
- Ok(self)
- }
-}
-
-impl fmt::Write for SymbolPrinter<'_, '_> {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- // Name sanitation. LLVM will happily accept identifiers with weird names, but
- // gas doesn't!
- // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
- // NVPTX assembly has more strict naming rules than gas, so additionally, dots
- // are replaced with '$' there.
-
- for c in s.chars() {
- if self.path.temp_buf.is_empty() {
- match c {
- 'a'..='z' | 'A'..='Z' | '_' => {}
- _ => {
- // Underscore-qualify anything that didn't start as an ident.
- self.path.temp_buf.push('_');
- }
- }
- }
- match c {
- // Escape these with $ sequences
- '@' => self.path.temp_buf.push_str("$SP$"),
- '*' => self.path.temp_buf.push_str("$BP$"),
- '&' => self.path.temp_buf.push_str("$RF$"),
- '<' => self.path.temp_buf.push_str("$LT$"),
- '>' => self.path.temp_buf.push_str("$GT$"),
- '(' => self.path.temp_buf.push_str("$LP$"),
- ')' => self.path.temp_buf.push_str("$RP$"),
- ',' => self.path.temp_buf.push_str("$C$"),
-
- '-' | ':' | '.' if self.tcx.has_strict_asm_symbol_naming() => {
- // NVPTX doesn't support these characters in symbol names.
- self.path.temp_buf.push('$')
- }
-
- // '.' doesn't occur in types and functions, so reuse it
- // for ':' and '-'
- '-' | ':' => self.path.temp_buf.push('.'),
-
- // Avoid segmentation fault on some platforms, see #60925.
- 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$6d$"),
+ LOCAL_CRATE
+ })
+ } else {
+ None
+ };
- // These are legal symbols
- 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c),
+ // Pick the crate responsible for the symbol mangling version, which has to:
+ // 1. be stable for each instance, whether it's being defined or imported
+ // 2. obey each crate's own `-Z symbol-mangling-version`, as much as possible
+ // We solve these as follows:
+ // 1. because symbol names depend on both `def_id` and `instantiating_crate`,
+ // both their `CrateNum`s are stable for any given instance, so we can pick
+ // either and have a stable choice of symbol mangling version
+ // 2. we favor `instantiating_crate` where possible (i.e. when `Some`)
+ let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate);
+ let mangling_version = if mangling_version_crate == LOCAL_CRATE {
+ tcx.sess.opts.debugging_opts.symbol_mangling_version
+ } else {
+ tcx.symbol_mangling_version(mangling_version_crate)
+ };
- _ => {
- self.path.temp_buf.push('$');
- for c in c.escape_unicode().skip(1) {
- match c {
- '{' => {}
- '}' => self.path.temp_buf.push('$'),
- c => self.path.temp_buf.push(c),
- }
- }
- }
- }
- }
+ let mangled = match mangling_version {
+ SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
+ SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate),
+ };
- Ok(())
- }
+ InternedString::intern(&mangled)
}
--- /dev/null
+use rustc::hir::def_id::CrateNum;
+use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
+use rustc::ich::NodeIdHashingMode;
+use rustc::mir::interpret::{ConstValue, Scalar};
+use rustc::ty::print::{PrettyPrinter, Printer, Print};
+use rustc::ty::subst::{Kind, UnpackedKind};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::util::common::record_time;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_mir::monomorphize::Instance;
+
+use log::debug;
+
+use std::fmt::{self, Write};
+use std::mem::{self, discriminant};
+
+pub(super) fn mangle(
+ tcx: TyCtxt<'_, 'tcx, 'tcx>,
+ instance: Instance<'tcx>,
+ instantiating_crate: Option<CrateNum>,
+) -> String {
+ let def_id = instance.def_id();
+
+ // We want to compute the "type" of this item. Unfortunately, some
+ // kinds of items (e.g., closures) don't have an entry in the
+ // item-type array. So walk back up the find the closest parent
+ // that DOES have an entry.
+ let mut ty_def_id = def_id;
+ let instance_ty;
+ loop {
+ let key = tcx.def_key(ty_def_id);
+ match key.disambiguated_data.data {
+ DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => {
+ instance_ty = tcx.type_of(ty_def_id);
+ break;
+ }
+ _ => {
+ // if we're making a symbol for something, there ought
+ // to be a value or type-def or something in there
+ // *somewhere*
+ ty_def_id.index = key.parent.unwrap_or_else(|| {
+ bug!(
+ "finding type for {:?}, encountered def-id {:?} with no \
+ parent",
+ def_id,
+ ty_def_id
+ );
+ });
+ }
+ }
+ }
+
+ // Erase regions because they may not be deterministic when hashed
+ // and should not matter anyhow.
+ let instance_ty = tcx.erase_regions(&instance_ty);
+
+ let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
+
+ let mut printer = SymbolPrinter {
+ tcx,
+ path: SymbolPath::new(),
+ keep_within_component: false,
+ }.print_def_path(def_id, &[]).unwrap();
+
+ if instance.is_vtable_shim() {
+ let _ = printer.write_str("{{vtable-shim}}");
+ }
+
+ printer.path.finish(hash)
+}
+
+fn get_symbol_hash<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+
+ // instance this name will be for
+ instance: Instance<'tcx>,
+
+ // type of the item, without any generic
+ // parameters substituted; this is
+ // included in the hash as a kind of
+ // safeguard.
+ item_type: Ty<'tcx>,
+
+ instantiating_crate: Option<CrateNum>,
+) -> u64 {
+ let def_id = instance.def_id();
+ let substs = instance.substs;
+ debug!(
+ "get_symbol_hash(def_id={:?}, parameters={:?})",
+ def_id, substs
+ );
+
+ let mut hasher = StableHasher::<u64>::new();
+ let mut hcx = tcx.create_stable_hashing_context();
+
+ record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
+ // the main symbol name is not necessarily unique; hash in the
+ // compiler's internal def-path, guaranteeing each symbol has a
+ // truly unique path
+ tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
+
+ // Include the main item-type. Note that, in this case, the
+ // assertions about `needs_subst` may not hold, but this item-type
+ // ought to be the same for every reference anyway.
+ assert!(!item_type.has_erasable_regions());
+ hcx.while_hashing_spans(false, |hcx| {
+ hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+ item_type.hash_stable(hcx, &mut hasher);
+ });
+ });
+
+ // If this is a function, we hash the signature as well.
+ // This is not *strictly* needed, but it may help in some
+ // situations, see the `run-make/a-b-a-linker-guard` test.
+ if let ty::FnDef(..) = item_type.sty {
+ item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher);
+ }
+
+ // also include any type parameters (for generic items)
+ assert!(!substs.has_erasable_regions());
+ assert!(!substs.needs_subst());
+ substs.hash_stable(&mut hcx, &mut hasher);
+
+ if let Some(instantiating_crate) = instantiating_crate {
+ (&tcx.original_crate_name(instantiating_crate).as_str()[..])
+ .hash_stable(&mut hcx, &mut hasher);
+ (&tcx.crate_disambiguator(instantiating_crate)).hash_stable(&mut hcx, &mut hasher);
+ }
+
+ // We want to avoid accidental collision between different types of instances.
+ // Especially, VtableShim may overlap with its original instance without this.
+ discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher);
+ });
+
+ // 64 bits should be enough to avoid collisions.
+ hasher.finish()
+}
+
+// Follow C++ namespace-mangling style, see
+// http://en.wikipedia.org/wiki/Name_mangling for more info.
+//
+// It turns out that on macOS you can actually have arbitrary symbols in
+// function names (at least when given to LLVM), but this is not possible
+// when using unix's linker. Perhaps one day when we just use a linker from LLVM
+// we won't need to do this name mangling. The problem with name mangling is
+// that it seriously limits the available characters. For example we can't
+// have things like &T in symbol names when one would theoretically
+// want them for things like impls of traits on that type.
+//
+// To be able to work on all platforms and get *some* reasonable output, we
+// use C++ name-mangling.
+#[derive(Debug)]
+struct SymbolPath {
+ result: String,
+ temp_buf: String,
+}
+
+impl SymbolPath {
+ fn new() -> Self {
+ let mut result = SymbolPath {
+ result: String::with_capacity(64),
+ temp_buf: String::with_capacity(16),
+ };
+ result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
+ result
+ }
+
+ fn finalize_pending_component(&mut self) {
+ if !self.temp_buf.is_empty() {
+ let _ = write!(self.result, "{}{}", self.temp_buf.len(), self.temp_buf);
+ self.temp_buf.clear();
+ }
+ }
+
+ fn finish(mut self, hash: u64) -> String {
+ self.finalize_pending_component();
+ // E = end name-sequence
+ let _ = write!(self.result, "17h{:016x}E", hash);
+ self.result
+ }
+}
+
+struct SymbolPrinter<'a, 'tcx> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ path: SymbolPath,
+
+ // When `true`, `finalize_pending_component` isn't used.
+ // This is needed when recursing into `path_qualified`,
+ // or `path_generic_args`, as any nested paths are
+ // logically within one component.
+ keep_within_component: bool,
+}
+
+// HACK(eddyb) this relies on using the `fmt` interface to get
+// `PrettyPrinter` aka pretty printing of e.g. types in paths,
+// symbol names should have their own printing machinery.
+
+impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
+ type Error = fmt::Error;
+
+ type Path = Self;
+ type Region = Self;
+ type Type = Self;
+ type DynExistential = Self;
+ type Const = Self;
+
+ fn tcx(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
+ self.tcx
+ }
+
+ fn print_region(
+ self,
+ _region: ty::Region<'_>,
+ ) -> Result<Self::Region, Self::Error> {
+ Ok(self)
+ }
+
+ fn print_type(
+ self,
+ ty: Ty<'tcx>,
+ ) -> Result<Self::Type, Self::Error> {
+ match ty.sty {
+ // Print all nominal types as paths (unlike `pretty_print_type`).
+ ty::FnDef(def_id, substs) |
+ ty::Opaque(def_id, substs) |
+ ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) |
+ ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) |
+ ty::Closure(def_id, ty::ClosureSubsts { substs }) |
+ ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => {
+ self.print_def_path(def_id, substs)
+ }
+ _ => self.pretty_print_type(ty),
+ }
+ }
+
+ fn print_dyn_existential(
+ mut self,
+ predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
+ ) -> Result<Self::DynExistential, Self::Error> {
+ let mut first = true;
+ for p in predicates {
+ if !first {
+ write!(self, "+")?;
+ }
+ first = false;
+ self = p.print(self)?;
+ }
+ Ok(self)
+ }
+
+ fn print_const(
+ mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<Self::Const, Self::Error> {
+ // only print integers
+ if let ConstValue::Scalar(Scalar::Raw { .. }) = ct.val {
+ if ct.ty.is_integral() {
+ return self.pretty_print_const(ct);
+ }
+ }
+ self.write_str("_")?;
+ Ok(self)
+ }
+
+ fn path_crate(
+ mut self,
+ cnum: CrateNum,
+ ) -> Result<Self::Path, Self::Error> {
+ self.write_str(&self.tcx.original_crate_name(cnum).as_str())?;
+ Ok(self)
+ }
+ fn path_qualified(
+ self,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Result<Self::Path, Self::Error> {
+ // Similar to `pretty_path_qualified`, but for the other
+ // types that are printed as paths (see `print_type` above).
+ match self_ty.sty {
+ ty::FnDef(..) |
+ ty::Opaque(..) |
+ ty::Projection(_) |
+ ty::UnnormalizedProjection(_) |
+ ty::Closure(..) |
+ ty::Generator(..)
+ if trait_ref.is_none() =>
+ {
+ self.print_type(self_ty)
+ }
+
+ _ => self.pretty_path_qualified(self_ty, trait_ref)
+ }
+ }
+
+ fn path_append_impl(
+ self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ _disambiguated_data: &DisambiguatedDefPathData,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Result<Self::Path, Self::Error> {
+ self.pretty_path_append_impl(
+ |mut cx| {
+ cx = print_prefix(cx)?;
+
+ if cx.keep_within_component {
+ // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it.
+ cx.write_str("::")?;
+ } else {
+ cx.path.finalize_pending_component();
+ }
+
+ Ok(cx)
+ },
+ self_ty,
+ trait_ref,
+ )
+ }
+ fn path_append(
+ mut self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ disambiguated_data: &DisambiguatedDefPathData,
+ ) -> Result<Self::Path, Self::Error> {
+ self = print_prefix(self)?;
+
+ // Skip `::{{constructor}}` on tuple/unit structs.
+ match disambiguated_data.data {
+ DefPathData::Ctor => return Ok(self),
+ _ => {}
+ }
+
+ if self.keep_within_component {
+ // HACK(eddyb) print the path similarly to how `FmtPrinter` prints it.
+ self.write_str("::")?;
+ } else {
+ self.path.finalize_pending_component();
+ }
+
+ self.write_str(&disambiguated_data.data.as_interned_str().as_str())?;
+ Ok(self)
+ }
+ fn path_generic_args(
+ mut self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ args: &[Kind<'tcx>],
+ ) -> Result<Self::Path, Self::Error> {
+ self = print_prefix(self)?;
+
+ let args = args.iter().cloned().filter(|arg| {
+ match arg.unpack() {
+ UnpackedKind::Lifetime(_) => false,
+ _ => true,
+ }
+ });
+
+ if args.clone().next().is_some() {
+ self.generic_delimiters(|cx| cx.comma_sep(args))
+ } else {
+ Ok(self)
+ }
+ }
+}
+
+impl PrettyPrinter<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
+ fn region_should_not_be_omitted(
+ &self,
+ _region: ty::Region<'_>,
+ ) -> bool {
+ false
+ }
+ fn comma_sep<T>(
+ mut self,
+ mut elems: impl Iterator<Item = T>,
+ ) -> Result<Self, Self::Error>
+ where T: Print<'tcx, 'tcx, Self, Output = Self, Error = Self::Error>
+ {
+ if let Some(first) = elems.next() {
+ self = first.print(self)?;
+ for elem in elems {
+ self.write_str(",")?;
+ self = elem.print(self)?;
+ }
+ }
+ Ok(self)
+ }
+
+ fn generic_delimiters(
+ mut self,
+ f: impl FnOnce(Self) -> Result<Self, Self::Error>,
+ ) -> Result<Self, Self::Error> {
+ write!(self, "<")?;
+
+ let kept_within_component =
+ mem::replace(&mut self.keep_within_component, true);
+ self = f(self)?;
+ self.keep_within_component = kept_within_component;
+
+ write!(self, ">")?;
+
+ Ok(self)
+ }
+}
+
+impl fmt::Write for SymbolPrinter<'_, '_> {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ // Name sanitation. LLVM will happily accept identifiers with weird names, but
+ // gas doesn't!
+ // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
+ // NVPTX assembly has more strict naming rules than gas, so additionally, dots
+ // are replaced with '$' there.
+
+ for c in s.chars() {
+ if self.path.temp_buf.is_empty() {
+ match c {
+ 'a'..='z' | 'A'..='Z' | '_' => {}
+ _ => {
+ // Underscore-qualify anything that didn't start as an ident.
+ self.path.temp_buf.push('_');
+ }
+ }
+ }
+ match c {
+ // Escape these with $ sequences
+ '@' => self.path.temp_buf.push_str("$SP$"),
+ '*' => self.path.temp_buf.push_str("$BP$"),
+ '&' => self.path.temp_buf.push_str("$RF$"),
+ '<' => self.path.temp_buf.push_str("$LT$"),
+ '>' => self.path.temp_buf.push_str("$GT$"),
+ '(' => self.path.temp_buf.push_str("$LP$"),
+ ')' => self.path.temp_buf.push_str("$RP$"),
+ ',' => self.path.temp_buf.push_str("$C$"),
+
+ '-' | ':' | '.' if self.tcx.has_strict_asm_symbol_naming() => {
+ // NVPTX doesn't support these characters in symbol names.
+ self.path.temp_buf.push('$')
+ }
+
+ // '.' doesn't occur in types and functions, so reuse it
+ // for ':' and '-'
+ '-' | ':' => self.path.temp_buf.push('.'),
+
+ // Avoid crashing LLVM in certain (LTO-related) situations, see #60925.
+ 'm' if self.path.temp_buf.ends_with(".llv") => self.path.temp_buf.push_str("$6d$"),
+
+ // These are legal symbols
+ 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => self.path.temp_buf.push(c),
+
+ _ => {
+ self.path.temp_buf.push('$');
+ for c in c.escape_unicode().skip(1) {
+ match c {
+ '{' => {}
+ '}' => self.path.temp_buf.push('$'),
+ c => self.path.temp_buf.push(c),
+ }
+ }
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
--- /dev/null
+use rustc::hir;
+use rustc::hir::def_id::{CrateNum, DefId};
+use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::print::{Printer, Print};
+use rustc::ty::subst::{Kind, Subst, UnpackedKind};
+use rustc_data_structures::base_n;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_mir::monomorphize::Instance;
+use rustc_target::spec::abi::Abi;
+use syntax::ast::{IntTy, UintTy, FloatTy};
+
+use std::fmt::Write;
+use std::ops::Range;
+
+pub(super) fn mangle(
+ tcx: TyCtxt<'_, 'tcx, 'tcx>,
+ instance: Instance<'tcx>,
+ instantiating_crate: Option<CrateNum>,
+) -> String {
+ let def_id = instance.def_id();
+ // FIXME(eddyb) this should ideally not be needed.
+ let substs =
+ tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.substs);
+
+ let prefix = "_R";
+ let mut cx = SymbolMangler {
+ tcx,
+ compress: Some(Box::new(CompressionCaches {
+ start_offset: prefix.len(),
+
+ paths: FxHashMap::default(),
+ types: FxHashMap::default(),
+ consts: FxHashMap::default(),
+ })),
+ binders: vec![],
+ out: String::from(prefix),
+ };
+ cx = if instance.is_vtable_shim() {
+ cx.path_append_ns(
+ |cx| cx.print_def_path(def_id, substs),
+ 'S',
+ 0,
+ "",
+ ).unwrap()
+ } else {
+ cx.print_def_path(def_id, substs).unwrap()
+ };
+ if let Some(instantiating_crate) = instantiating_crate {
+ cx = cx.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap();
+ }
+ cx.out
+}
+
+struct CompressionCaches<'tcx> {
+ // The length of the prefix in `out` (e.g. 2 for `_R`).
+ start_offset: usize,
+
+ // The values are start positions in `out`, in bytes.
+ paths: FxHashMap<(DefId, &'tcx [Kind<'tcx>]), usize>,
+ types: FxHashMap<Ty<'tcx>, usize>,
+ consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+}
+
+struct BinderLevel {
+ /// The range of distances from the root of what's
+ /// being printed, to the lifetimes in a binder.
+ /// Specifically, a `BrAnon(i)` lifetime has depth
+ /// `lifetime_depths.start + i`, going away from the
+ /// the root and towards its use site, as `i` increases.
+ /// This is used to flatten rustc's pairing of `BrAnon`
+ /// (intra-binder disambiguation) with a `DebruijnIndex`
+ /// (binder addressing), to "true" de Bruijn indices,
+ /// by subtracting the depth of a certain lifetime, from
+ /// the innermost depth at its use site.
+ lifetime_depths: Range<u32>,
+}
+
+struct SymbolMangler<'a, 'tcx> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ compress: Option<Box<CompressionCaches<'tcx>>>,
+ binders: Vec<BinderLevel>,
+ out: String,
+}
+
+impl SymbolMangler<'_, 'tcx> {
+ fn push(&mut self, s: &str) {
+ self.out.push_str(s);
+ }
+
+ /// Push a `_`-terminated base 62 integer, using the format
+ /// specified in the RFC as `<base-62-number>`, that is:
+ /// * `x = 0` is encoded as just the `"_"` terminator
+ /// * `x > 0` is encoded as `x - 1` in base 62, followed by `"_"`,
+ /// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc.
+ fn push_integer_62(&mut self, x: u64) {
+ if let Some(x) = x.checked_sub(1) {
+ base_n::push_str(x as u128, 62, &mut self.out);
+ }
+ self.push("_");
+ }
+
+ /// Push a `tag`-prefixed base 62 integer, when larger than `0`, that is:
+ /// * `x = 0` is encoded as `""` (nothing)
+ /// * `x > 0` is encoded as the `tag` followed by `push_integer_62(x - 1)`
+ /// e.g. `1` becomes `tag + "_"`, `2` becomes `tag + "0_"`, etc.
+ fn push_opt_integer_62(&mut self, tag: &str, x: u64) {
+ if let Some(x) = x.checked_sub(1) {
+ self.push(tag);
+ self.push_integer_62(x);
+ }
+ }
+
+ fn push_disambiguator(&mut self, dis: u64) {
+ self.push_opt_integer_62("s", dis);
+ }
+
+ fn push_ident(&mut self, ident: &str) {
+ let mut use_punycode = false;
+ for b in ident.bytes() {
+ match b {
+ b'_' | b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' => {}
+ 0x80..=0xff => use_punycode = true,
+ _ => bug!("symbol_names: bad byte {} in ident {:?}", b, ident),
+ }
+ }
+
+ let punycode_string;
+ let ident = if use_punycode {
+ self.push("u");
+
+ // FIXME(eddyb) we should probably roll our own punycode implementation.
+ let mut punycode_bytes = match ::punycode::encode(ident) {
+ Ok(s) => s.into_bytes(),
+ Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident),
+ };
+
+ // Replace `-` with `_`.
+ if let Some(c) = punycode_bytes.iter_mut().rfind(|&&mut c| c == b'-') {
+ *c = b'_';
+ }
+
+ // FIXME(eddyb) avoid rechecking UTF-8 validity.
+ punycode_string = String::from_utf8(punycode_bytes).unwrap();
+ &punycode_string
+ } else {
+ ident
+ };
+
+ let _ = write!(self.out, "{}", ident.len());
+
+ // Write a separating `_` if necessary (leading digit or `_`).
+ match ident.chars().next() {
+ Some('_') | Some('0'..='9') => {
+ self.push("_");
+ }
+ _ => {}
+ }
+
+ self.push(ident);
+ }
+
+ fn path_append_ns(
+ mut self,
+ print_prefix: impl FnOnce(Self) -> Result<Self, !>,
+ ns: char,
+ disambiguator: u64,
+ name: &str,
+ ) -> Result<Self, !> {
+ self.push("N");
+ self.out.push(ns);
+ self = print_prefix(self)?;
+ self.push_disambiguator(disambiguator as u64);
+ self.push_ident(name);
+ Ok(self)
+ }
+
+ fn print_backref(mut self, i: usize) -> Result<Self, !> {
+ self.push("B");
+ self.push_integer_62((i - self.compress.as_ref().unwrap().start_offset) as u64);
+ Ok(self)
+ }
+
+ fn in_binder<T>(
+ mut self,
+ value: &ty::Binder<T>,
+ print_value: impl FnOnce(Self, &T) -> Result<Self, !>
+ ) -> Result<Self, !>
+ where T: TypeFoldable<'tcx>
+ {
+ let regions = if value.has_late_bound_regions() {
+ self.tcx.collect_referenced_late_bound_regions(value)
+ } else {
+ FxHashSet::default()
+ };
+
+ let mut lifetime_depths =
+ self.binders.last().map(|b| b.lifetime_depths.end).map_or(0..0, |i| i..i);
+
+ let lifetimes = regions.into_iter().map(|br| {
+ match br {
+ ty::BrAnon(i) => i + 1,
+ _ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value),
+ }
+ }).max().unwrap_or(0);
+
+ self.push_opt_integer_62("G", lifetimes as u64);
+ lifetime_depths.end += lifetimes;
+
+ self.binders.push(BinderLevel { lifetime_depths });
+ self = print_value(self, value.skip_binder())?;
+ self.binders.pop();
+
+ Ok(self)
+ }
+}
+
+impl Printer<'tcx, 'tcx> for SymbolMangler<'_, 'tcx> {
+ type Error = !;
+
+ type Path = Self;
+ type Region = Self;
+ type Type = Self;
+ type DynExistential = Self;
+ type Const = Self;
+
+ fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
+ self.tcx
+ }
+
+ fn print_def_path(
+ mut self,
+ def_id: DefId,
+ substs: &'tcx [Kind<'tcx>],
+ ) -> Result<Self::Path, Self::Error> {
+ if let Some(&i) = self.compress.as_ref().and_then(|c| c.paths.get(&(def_id, substs))) {
+ return self.print_backref(i);
+ }
+ let start = self.out.len();
+
+ self = self.default_print_def_path(def_id, substs)?;
+
+ // Only cache paths that do not refer to an enclosing
+ // binder (which would change depending on context).
+ if !substs.iter().any(|k| k.has_escaping_bound_vars()) {
+ if let Some(c) = &mut self.compress {
+ c.paths.insert((def_id, substs), start);
+ }
+ }
+ Ok(self)
+ }
+
+ fn print_impl_path(
+ self,
+ impl_def_id: DefId,
+ substs: &'tcx [Kind<'tcx>],
+ mut self_ty: Ty<'tcx>,
+ mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Result<Self::Path, Self::Error> {
+ let key = self.tcx.def_key(impl_def_id);
+ let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
+
+ let mut param_env = self.tcx.param_env(impl_def_id)
+ .with_reveal_all();
+ if !substs.is_empty() {
+ param_env = param_env.subst(self.tcx, substs);
+ }
+
+ match &mut impl_trait_ref {
+ Some(impl_trait_ref) => {
+ assert_eq!(impl_trait_ref.self_ty(), self_ty);
+ *impl_trait_ref =
+ self.tcx.normalize_erasing_regions(param_env, *impl_trait_ref);
+ self_ty = impl_trait_ref.self_ty();
+ }
+ None => {
+ self_ty = self.tcx.normalize_erasing_regions(param_env, self_ty);
+ }
+ }
+
+ self.path_append_impl(
+ |cx| cx.print_def_path(parent_def_id, &[]),
+ &key.disambiguated_data,
+ self_ty,
+ impl_trait_ref,
+ )
+ }
+
+ fn print_region(
+ mut self,
+ region: ty::Region<'_>,
+ ) -> Result<Self::Region, Self::Error> {
+ let i = match *region {
+ // Erased lifetimes use the index 0, for a
+ // shorter mangling of `L_`.
+ ty::ReErased => 0,
+
+ // Late-bound lifetimes use indices starting at 1,
+ // see `BinderLevel` for more details.
+ ty::ReLateBound(debruijn, ty::BrAnon(i)) => {
+ let binder = &self.binders[self.binders.len() - 1 - debruijn.index()];
+ let depth = binder.lifetime_depths.start + i;
+
+ 1 + (self.binders.last().unwrap().lifetime_depths.end - 1 - depth)
+ }
+
+ _ => bug!("symbol_names: non-erased region `{:?}`", region),
+ };
+ self.push("L");
+ self.push_integer_62(i as u64);
+ Ok(self)
+ }
+
+ fn print_type(
+ mut self,
+ ty: Ty<'tcx>,
+ ) -> Result<Self::Type, Self::Error> {
+ // Basic types, never cached (single-character).
+ let basic_type = match ty.sty {
+ ty::Bool => "b",
+ ty::Char => "c",
+ ty::Str => "e",
+ ty::Tuple(_) if ty.is_unit() => "u",
+ ty::Int(IntTy::I8) => "a",
+ ty::Int(IntTy::I16) => "s",
+ ty::Int(IntTy::I32) => "l",
+ ty::Int(IntTy::I64) => "x",
+ ty::Int(IntTy::I128) => "n",
+ ty::Int(IntTy::Isize) => "i",
+ ty::Uint(UintTy::U8) => "h",
+ ty::Uint(UintTy::U16) => "t",
+ ty::Uint(UintTy::U32) => "m",
+ ty::Uint(UintTy::U64) => "y",
+ ty::Uint(UintTy::U128) => "o",
+ ty::Uint(UintTy::Usize) => "j",
+ ty::Float(FloatTy::F32) => "f",
+ ty::Float(FloatTy::F64) => "d",
+ ty::Never => "z",
+
+ // Placeholders (should be demangled as `_`).
+ ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) |
+ ty::Infer(_) | ty::Error => "p",
+
+ _ => "",
+ };
+ if !basic_type.is_empty() {
+ self.push(basic_type);
+ return Ok(self);
+ }
+
+ if let Some(&i) = self.compress.as_ref().and_then(|c| c.types.get(&ty)) {
+ return self.print_backref(i);
+ }
+ let start = self.out.len();
+
+ match ty.sty {
+ // Basic types, handled above.
+ ty::Bool | ty::Char | ty::Str |
+ ty::Int(_) | ty::Uint(_) | ty::Float(_) |
+ ty::Never => unreachable!(),
+ ty::Tuple(_) if ty.is_unit() => unreachable!(),
+
+ // Placeholders, also handled as part of basic types.
+ ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) |
+ ty::Infer(_) | ty::Error => unreachable!(),
+
+ ty::Ref(r, ty, mutbl) => {
+ self.push(match mutbl {
+ hir::MutImmutable => "R",
+ hir::MutMutable => "Q",
+ });
+ if *r != ty::ReErased {
+ self = r.print(self)?;
+ }
+ self = ty.print(self)?;
+ }
+
+ ty::RawPtr(mt) => {
+ self.push(match mt.mutbl {
+ hir::MutImmutable => "P",
+ hir::MutMutable => "O",
+ });
+ self = mt.ty.print(self)?;
+ }
+
+ ty::Array(ty, len) => {
+ self.push("A");
+ self = ty.print(self)?;
+ self = self.print_const(len)?;
+ }
+ ty::Slice(ty) => {
+ self.push("S");
+ self = ty.print(self)?;
+ }
+
+ ty::Tuple(tys) => {
+ self.push("T");
+ for ty in tys.iter().map(|k| k.expect_ty()) {
+ self = ty.print(self)?;
+ }
+ self.push("E");
+ }
+
+ // Mangle all nominal types as paths.
+ ty::Adt(&ty::AdtDef { did: def_id, .. }, substs) |
+ ty::FnDef(def_id, substs) |
+ ty::Opaque(def_id, substs) |
+ ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs }) |
+ ty::UnnormalizedProjection(ty::ProjectionTy { item_def_id: def_id, substs }) |
+ ty::Closure(def_id, ty::ClosureSubsts { substs }) |
+ ty::Generator(def_id, ty::GeneratorSubsts { substs }, _) => {
+ self = self.print_def_path(def_id, substs)?;
+ }
+ ty::Foreign(def_id) => {
+ self = self.print_def_path(def_id, &[])?;
+ }
+
+ ty::FnPtr(sig) => {
+ self.push("F");
+ self = self.in_binder(&sig, |mut cx, sig| {
+ if sig.unsafety == hir::Unsafety::Unsafe {
+ cx.push("U");
+ }
+ match sig.abi {
+ Abi::Rust => {}
+ Abi::C => cx.push("KC"),
+ abi => {
+ cx.push("K");
+ let name = abi.name();
+ if name.contains('-') {
+ cx.push_ident(&name.replace('-', "_"));
+ } else {
+ cx.push_ident(name);
+ }
+ }
+ }
+ for &ty in sig.inputs() {
+ cx = ty.print(cx)?;
+ }
+ if sig.c_variadic {
+ cx.push("v");
+ }
+ cx.push("E");
+ sig.output().print(cx)
+ })?;
+ }
+
+ ty::Dynamic(predicates, r) => {
+ self.push("D");
+ self = self.in_binder(&predicates, |cx, predicates| {
+ cx.print_dyn_existential(predicates)
+ })?;
+ self = r.print(self)?;
+ }
+
+ ty::GeneratorWitness(_) => {
+ bug!("symbol_names: unexpected `GeneratorWitness`")
+ }
+ }
+
+ // Only cache types that do not refer to an enclosing
+ // binder (which would change depending on context).
+ if !ty.has_escaping_bound_vars() {
+ if let Some(c) = &mut self.compress {
+ c.types.insert(ty, start);
+ }
+ }
+ Ok(self)
+ }
+
+ fn print_dyn_existential(
+ mut self,
+ predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
+ ) -> Result<Self::DynExistential, Self::Error> {
+ for predicate in predicates {
+ match *predicate {
+ ty::ExistentialPredicate::Trait(trait_ref) => {
+ // Use a type that can't appear in defaults of type parameters.
+ let dummy_self = self.tcx.mk_ty_infer(ty::FreshTy(0));
+ let trait_ref = trait_ref.with_self_ty(self.tcx, dummy_self);
+ self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?;
+ }
+ ty::ExistentialPredicate::Projection(projection) => {
+ let name = self.tcx.associated_item(projection.item_def_id).ident;
+ self.push("p");
+ self.push_ident(&name.as_str());
+ self = projection.ty.print(self)?;
+ }
+ ty::ExistentialPredicate::AutoTrait(def_id) => {
+ self = self.print_def_path(def_id, &[])?;
+ }
+ }
+ }
+ self.push("E");
+ Ok(self)
+ }
+
+ fn print_const(
+ mut self,
+ ct: &'tcx ty::Const<'tcx>,
+ ) -> Result<Self::Const, Self::Error> {
+ if let Some(&i) = self.compress.as_ref().and_then(|c| c.consts.get(&ct)) {
+ return self.print_backref(i);
+ }
+ let start = self.out.len();
+
+ match ct.ty.sty {
+ ty::Uint(_) => {}
+ _ => {
+ bug!("symbol_names: unsupported constant of type `{}` ({:?})",
+ ct.ty, ct);
+ }
+ }
+ self = ct.ty.print(self)?;
+
+ if let Some(bits) = ct.assert_bits(self.tcx, ty::ParamEnv::empty().and(ct.ty)) {
+ let _ = write!(self.out, "{:x}_", bits);
+ } else {
+ // NOTE(eddyb) despite having the path, we need to
+ // encode a placeholder, as the path could refer
+ // back to e.g. an `impl` using the constant.
+ self.push("p");
+ }
+
+ // Only cache consts that do not refer to an enclosing
+ // binder (which would change depending on context).
+ if !ct.has_escaping_bound_vars() {
+ if let Some(c) = &mut self.compress {
+ c.consts.insert(ct, start);
+ }
+ }
+ Ok(self)
+ }
+
+ fn path_crate(
+ mut self,
+ cnum: CrateNum,
+ ) -> Result<Self::Path, Self::Error> {
+ self.push("C");
+ let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint();
+ self.push_disambiguator(fingerprint.to_smaller_hash());
+ let name = self.tcx.original_crate_name(cnum).as_str();
+ self.push_ident(&name);
+ Ok(self)
+ }
+ fn path_qualified(
+ mut self,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Result<Self::Path, Self::Error> {
+ assert!(trait_ref.is_some());
+ let trait_ref = trait_ref.unwrap();
+
+ self.push("Y");
+ self = self_ty.print(self)?;
+ self.print_def_path(trait_ref.def_id, trait_ref.substs)
+ }
+
+ fn path_append_impl(
+ mut self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ disambiguated_data: &DisambiguatedDefPathData,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Result<Self::Path, Self::Error> {
+ self.push(match trait_ref {
+ Some(_) => "X",
+ None => "M",
+ });
+ self.push_disambiguator(disambiguated_data.disambiguator as u64);
+ self = print_prefix(self)?;
+ self = self_ty.print(self)?;
+ if let Some(trait_ref) = trait_ref {
+ self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?;
+ }
+ Ok(self)
+ }
+ fn path_append(
+ self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ disambiguated_data: &DisambiguatedDefPathData,
+ ) -> Result<Self::Path, Self::Error> {
+ let ns = match disambiguated_data.data {
+ // Uppercase categories are more stable than lowercase ones.
+ DefPathData::TypeNs(_) => 't',
+ DefPathData::ValueNs(_) => 'v',
+ DefPathData::ClosureExpr => 'C',
+ DefPathData::Ctor => 'c',
+ DefPathData::AnonConst => 'k',
+ DefPathData::ImplTrait => 'i',
+
+ // These should never show up as `path_append` arguments.
+ DefPathData::CrateRoot
+ | DefPathData::Misc
+ | DefPathData::Impl
+ | DefPathData::MacroNs(_)
+ | DefPathData::LifetimeNs(_)
+ | DefPathData::GlobalMetaData(_) => {
+ bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data)
+ }
+ };
+
+ let name = disambiguated_data.data.get_opt_name().map(|s| s.as_str());
+
+ self.path_append_ns(
+ print_prefix,
+ ns,
+ disambiguated_data.disambiguator as u64,
+ name.as_ref().map_or("", |s| &s[..])
+ )
+ }
+ fn path_generic_args(
+ mut self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ args: &[Kind<'tcx>],
+ ) -> Result<Self::Path, Self::Error> {
+ // Don't print any regions if they're all erased.
+ let print_regions = args.iter().any(|arg| {
+ match arg.unpack() {
+ UnpackedKind::Lifetime(r) => *r != ty::ReErased,
+ _ => false,
+ }
+ });
+ let args = args.iter().cloned().filter(|arg| {
+ match arg.unpack() {
+ UnpackedKind::Lifetime(_) => print_regions,
+ _ => true,
+ }
+ });
+
+ if args.clone().next().is_none() {
+ return print_prefix(self);
+ }
+
+ self.push("I");
+ self = print_prefix(self)?;
+ for arg in args {
+ match arg.unpack() {
+ UnpackedKind::Lifetime(lt) => {
+ self = lt.print(self)?;
+ }
+ UnpackedKind::Type(ty) => {
+ self = ty.print(self)?;
+ }
+ UnpackedKind::Const(c) => {
+ self.push("K");
+ // FIXME(const_generics) implement `ty::print::Print` on `ty::Const`.
+ // self = c.print(self)?;
+ self = self.print_const(c)?;
+ }
+ }
+ }
+ self.push("E");
+
+ Ok(self)
+ }
+}
if attr.check_name(SYMBOL_NAME) {
// for now, can only use on monomorphic names
let instance = Instance::mono(tcx, def_id);
- let name = self.tcx.symbol_name(instance);
- tcx.sess.span_err(attr.span, &format!("symbol-name({})", name));
+ let mangled = self.tcx.symbol_name(instance);
+ tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled));
+ if let Ok(demangling) = rustc_demangle::try_demangle(&mangled.as_str()) {
+ tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
+ tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
+ }
} else if attr.check_name(DEF_PATH) {
let path = tcx.def_path_str(def_id);
tcx.sess.span_err(attr.span, &format!("def-path({})", path));
declare_lint! {
pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
- Allow,
+ Warn,
"`...` range patterns are deprecated"
}
r.map(|c| &*tcx.arena.alloc(c))
}
is_no_builtins => { cdata.root.no_builtins }
+ symbol_mangling_version => { cdata.root.symbol_mangling_version }
impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
reachable_non_generics => {
let reachable_non_generics = tcx
panic_runtime: attr::contains_name(&attrs, sym::panic_runtime),
profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime),
sanitizer_runtime: attr::contains_name(&attrs, sym::sanitizer_runtime),
+ symbol_mangling_version: tcx.sess.opts.debugging_opts.symbol_mangling_version,
crate_deps,
dylib_dependency_formats,
use rustc::middle::lang_items;
use rustc::mir;
use rustc::session::CrateDisambiguator;
+use rustc::session::config::SymbolManglingVersion;
use rustc::ty::{self, Ty, ReprOptions};
use rustc_target::spec::{PanicStrategy, TargetTriple};
use rustc_data_structures::svh::Svh;
pub panic_runtime: bool,
pub profiler_runtime: bool,
pub sanitizer_runtime: bool,
+ pub symbol_mangling_version: SymbolManglingVersion,
}
#[derive(RustcEncodable, RustcDecodable)]
}
}
- ty::BoundRegion::BrAnon(_) | ty::BoundRegion::BrFresh(_) => None,
+ ty::BoundRegion::BrAnon(_) => None,
},
ty::ReLateBound(..)
ptr.offset.bytes(),
),
Scalar::Raw { .. } => (
- ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(b"", ())),
+ ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(
+ b"" as &[u8], (),
+ )),
0,
),
};
Machine, PlaceTy, OpTy, InterpretCx,
};
+mod type_name;
+
+pub use type_name::*;
fn numeric_intrinsic<'tcx, Tag>(
name: &str,
--- /dev/null
+use rustc::ty::{
+ TyCtxt, Ty,
+ subst::{UnpackedKind, Kind},
+ print::{Printer, PrettyPrinter, Print},
+ self,
+};
+use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
+use rustc::hir::def_id::CrateNum;
+use std::fmt::Write;
+use rustc::mir::interpret::{Allocation, ConstValue};
+
+struct AbsolutePathPrinter<'a, 'tcx> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ path: String,
+}
+
+impl<'tcx> Printer<'tcx, 'tcx> for AbsolutePathPrinter<'_, 'tcx> {
+ type Error = std::fmt::Error;
+
+ type Path = Self;
+ type Region = Self;
+ type Type = Self;
+ type DynExistential = Self;
+ type Const = Self;
+
+ fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
+ self.tcx
+ }
+
+ fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
+ Ok(self)
+ }
+
+ fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
+ match ty.sty {
+ // types without identity
+ | ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Str
+ | ty::Array(_, _)
+ | ty::Slice(_)
+ | ty::RawPtr(_)
+ | ty::Ref(_, _, _)
+ | ty::FnPtr(_)
+ | ty::Never
+ | ty::Tuple(_)
+ | ty::Dynamic(_, _)
+ | ty::Adt(..)
+ | ty::Foreign(_)
+ // should be unreachable, but there's no hurt in printing it (and better than ICEing)
+ | ty::Error
+ => self.pretty_print_type(ty),
+ | ty::Infer(_)
+ | ty::Bound(_, _)
+ | ty::Param(_)
+ | ty::Placeholder(_)
+ | ty::Projection(_)
+ | ty::UnnormalizedProjection(_)
+ | ty::GeneratorWitness(_)
+ => bug!(
+ "{:#?} in `type_name` should not happen because we are always monomorphized",
+ ty,
+ ),
+ // types with identity (print the module path instead)
+ | ty::FnDef(did, substs)
+ | ty::Opaque(did, substs)
+ => self.print_def_path(did, substs),
+ ty::Closure(did, substs) => self.print_def_path(did, substs.substs),
+ ty::Generator(did, substs, _) => self.print_def_path(did, substs.substs),
+ }
+ }
+
+ fn print_const(
+ self,
+ _: &'tcx ty::Const<'tcx>,
+ ) -> Result<Self::Const, Self::Error> {
+ // don't print constants to the user
+ Ok(self)
+ }
+
+ fn print_dyn_existential(
+ mut self,
+ predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
+ ) -> Result<Self::DynExistential, Self::Error> {
+ let mut first = true;
+ for p in predicates {
+ if !first {
+ write!(self, "+")?;
+ }
+ first = false;
+ self = p.print(self)?;
+ }
+ Ok(self)
+ }
+
+ fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
+ self.path.push_str(&self.tcx.original_crate_name(cnum).as_str());
+ Ok(self)
+ }
+
+ fn path_qualified(
+ self,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Result<Self::Path, Self::Error> {
+ self.pretty_path_qualified(self_ty, trait_ref)
+ }
+
+ fn path_append_impl(
+ self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ _disambiguated_data: &DisambiguatedDefPathData,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Result<Self::Path, Self::Error> {
+ self.pretty_path_append_impl(
+ |mut cx| {
+ cx = print_prefix(cx)?;
+
+ cx.path.push_str("::");
+
+ Ok(cx)
+ },
+ self_ty,
+ trait_ref,
+ )
+ }
+
+ fn path_append(
+ mut self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ disambiguated_data: &DisambiguatedDefPathData,
+ ) -> Result<Self::Path, Self::Error> {
+ self = print_prefix(self)?;
+
+ // Skip `::{{constructor}}` on tuple/unit structs.
+ match disambiguated_data.data {
+ DefPathData::Ctor => return Ok(self),
+ _ => {}
+ }
+
+ self.path.push_str("::");
+
+ self.path.push_str(&disambiguated_data.data.as_interned_str().as_str());
+ Ok(self)
+ }
+
+ fn path_generic_args(
+ mut self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ args: &[Kind<'tcx>],
+ ) -> Result<Self::Path, Self::Error> {
+ self = print_prefix(self)?;
+ let args = args.iter().cloned().filter(|arg| {
+ match arg.unpack() {
+ UnpackedKind::Lifetime(_) => false,
+ _ => true,
+ }
+ });
+ if args.clone().next().is_some() {
+ self.generic_delimiters(|cx| cx.comma_sep(args))
+ } else {
+ Ok(self)
+ }
+ }
+}
+impl PrettyPrinter<'tcx, 'tcx> for AbsolutePathPrinter<'_, 'tcx> {
+ fn region_should_not_be_omitted(
+ &self,
+ _region: ty::Region<'_>,
+ ) -> bool {
+ false
+ }
+ fn comma_sep<T>(
+ mut self,
+ mut elems: impl Iterator<Item = T>,
+ ) -> Result<Self, Self::Error>
+ where T: Print<'tcx, 'tcx, Self, Output = Self, Error = Self::Error>
+ {
+ if let Some(first) = elems.next() {
+ self = first.print(self)?;
+ for elem in elems {
+ self.path.push_str(", ");
+ self = elem.print(self)?;
+ }
+ }
+ Ok(self)
+ }
+
+ fn generic_delimiters(
+ mut self,
+ f: impl FnOnce(Self) -> Result<Self, Self::Error>,
+ ) -> Result<Self, Self::Error> {
+ write!(self, "<")?;
+
+ self = f(self)?;
+
+ write!(self, ">")?;
+
+ Ok(self)
+ }
+}
+
+impl Write for AbsolutePathPrinter<'_, '_> {
+ fn write_str(&mut self, s: &str) -> std::fmt::Result {
+ Ok(self.path.push_str(s))
+ }
+}
+
+/// Produces an absolute path representation of the given type. See also the documentation on
+/// `std::any::type_name`
+pub fn type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
+ let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
+ let len = path.len();
+ let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes(), ());
+ let alloc = tcx.intern_const_alloc(alloc);
+ tcx.mk_const(ty::Const {
+ val: ConstValue::Slice {
+ data: alloc,
+ start: 0,
+ end: len,
+ },
+ ty: tcx.mk_static_str(),
+ })
+}
pub use self::visitor::{ValueVisitor, MutValueVisitor};
pub use self::validity::RefTracking;
+
+pub use self::intrinsics::type_name;
#![feature(unicode_internals)]
#![feature(step_trait)]
#![feature(slice_concat_ext)]
-#![feature(reverse_bits)]
#![feature(try_blocks)]
#![recursion_limit="256"]
for br in late_bound_in_ret.difference(&late_bound_in_args) {
let lifetime_name = match *br {
ty::BrNamed(_, name) => format!("lifetime `{}`,", name),
- ty::BrAnon(_) | ty::BrFresh(_) | ty::BrEnv => "an anonymous lifetime".to_string(),
+ ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(),
};
let mut err = struct_span_err!(tcx.sess,
decl.output.span(),
}
}
if attrs.len() > 0 {
- write!(w, "<div class=\"docblock attributes{}\">{}</div>",
+ write!(w, "<span class=\"docblock attributes{}\">{}</span>",
if top { " top-attr" } else { "" }, &attrs)?;
}
Ok(())
/// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
/// ```
fn from(err: String) -> Box<dyn Error + Send + Sync> {
- #[derive(Debug)]
struct StringError(String);
impl Error for StringError {
}
}
+ // Purposefully skip printing "StringError(..)"
+ impl Debug for StringError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Debug::fmt(&self.0, f)
+ }
+ }
+
Box::new(StringError(err))
}
}
Applicability::MaybeIncorrect,
);
} else {
- err.note("type ascription is a nightly-only feature that lets \
- you annotate an expression with a type: `<expr>: <type>`")
+ err.note("#![feature(type_ascription)] lets you annotate an \
+ expression with a type: `<expr>: <type>`")
.span_note(
lhs_span,
"this expression expects an ascribed type after the colon",
return Ok(Some(item));
}
- // `unsafe async fn` or `async fn`
- if (
- self.check_keyword(kw::Unsafe) &&
- self.is_keyword_ahead(1, &[kw::Async])
- ) || (
- self.check_keyword(kw::Async) &&
- self.is_keyword_ahead(1, &[kw::Fn])
- )
- {
- // ASYNC FUNCTION ITEM
- let unsafety = self.parse_unsafety();
- self.expect_keyword(kw::Async)?;
- let async_span = self.prev_span;
- self.expect_keyword(kw::Fn)?;
- let fn_span = self.prev_span;
- let (ident, item_, extra_attrs) =
- self.parse_item_fn(unsafety,
- respan(async_span, IsAsync::Async {
- closure_id: ast::DUMMY_NODE_ID,
- return_impl_trait_id: ast::DUMMY_NODE_ID,
- arguments: Vec::new(),
- }),
- respan(fn_span, Constness::NotConst),
- Abi::Rust)?;
- let prev_span = self.prev_span;
- let item = self.mk_item(lo.to(prev_span),
- ident,
- item_,
- visibility,
- maybe_append(attrs, extra_attrs));
- if self.span.rust_2015() {
- self.diagnostic().struct_span_err_with_code(
- async_span,
- "`async fn` is not permitted in the 2015 edition",
- DiagnosticId::Error("E0670".into())
- ).emit();
+ // Parse `async unsafe? fn`.
+ if self.check_keyword(kw::Async) {
+ let async_span = self.span;
+ if self.is_keyword_ahead(1, &[kw::Fn])
+ || self.is_keyword_ahead(2, &[kw::Fn])
+ {
+ // ASYNC FUNCTION ITEM
+ self.bump(); // `async`
+ let unsafety = self.parse_unsafety(); // `unsafe`?
+ self.expect_keyword(kw::Fn)?; // `fn`
+ let fn_span = self.prev_span;
+ let (ident, item_, extra_attrs) =
+ self.parse_item_fn(unsafety,
+ respan(async_span, IsAsync::Async {
+ closure_id: ast::DUMMY_NODE_ID,
+ return_impl_trait_id: ast::DUMMY_NODE_ID,
+ arguments: Vec::new(),
+ }),
+ respan(fn_span, Constness::NotConst),
+ Abi::Rust)?;
+ let prev_span = self.prev_span;
+ let item = self.mk_item(lo.to(prev_span),
+ ident,
+ item_,
+ visibility,
+ maybe_append(attrs, extra_attrs));
+ if self.span.rust_2015() {
+ self.diagnostic().struct_span_err_with_code(
+ async_span,
+ "`async fn` is not permitted in the 2015 edition",
+ DiagnosticId::Error("E0670".into())
+ ).emit();
+ }
+ return Ok(Some(item));
}
- return Ok(Some(item));
}
if self.check_keyword(kw::Unsafe) &&
self.is_keyword_ahead(1, &[kw::Trait, kw::Auto])
if desc.allow_fail {
TrAllowedFail
} else {
- TrFailedMsg(format!("Panic did not include expected string '{}'", msg))
+ TrFailedMsg(format!("panic did not include expected string '{}'", msg))
}
}
}
panic!("an error message");
}
let expected = "foobar";
- let failed_msg = "Panic did not include expected string";
+ let failed_msg = "panic did not include expected string";
let desc = TestDescAndFn {
desc: TestDesc {
name: StaticTestName("whatever"),
// that's one new drop call per call to possibly_unwinding(), and finally 3 drop calls for the
// regular function exit. We used to have problems with quadratic growths of drop calls in such
// functions.
-// CHECK-NOT: invoke{{.*}}drop{{.*}}SomeUniqueName
-// CHECK: call{{.*}}drop{{.*}}SomeUniqueName
-// CHECK: call{{.*}}drop{{.*}}SomeUniqueName
-// CHECK-NOT: call{{.*}}drop{{.*}}SomeUniqueName
-// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName
-// CHECK: call{{.*}}drop{{.*}}SomeUniqueName
-// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName
-// CHECK: call{{.*}}drop{{.*}}SomeUniqueName
-// CHECK-NOT: {{(call|invoke).*}}drop{{.*}}SomeUniqueName
+// FIXME(eddyb) the `void @` forces a match on the instruction, instead of the
+// comment, that's `; call core::ptr::real_drop_in_place::<drop::SomeUniqueName>`
+// for the `v0` mangling, should switch to matching on that once `legacy` is gone.
+// CHECK-NOT: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
+// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
+// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
+// CHECK-NOT: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
+// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
+// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
+// CHECK: invoke void @{{.*}}drop_in_place{{.*}}SomeUniqueName
+// CHECK: call void @{{.*}}drop_in_place{{.*}}SomeUniqueName
+// CHECK-NOT: {{(call|invoke) void @.*}}drop_in_place{{.*}}SomeUniqueName
// The next line checks for the } that ends the function definition
// CHECK-LABEL: {{^[}]}}
let _s = SomeUniqueName;
};
// The surrounding item should not accidentally become external
-// CHECK: define internal{{.*}} void @_ZN22external_no_mangle_fns1x
+// CHECK-LABEL: ; external_no_mangle_fns::x
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define internal
#[inline(never)]
fn x() {
// CHECK: define void @g()
#[no_mangle]
pub static mut P: u8 = 0;
}
-// CHECK: define internal void @_ZN26external_no_mangle_statics1x{{.*$}}
+// CHECK-LABEL: ; external_no_mangle_statics::x
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define internal
// We want to make sure that closures get 'internal' linkage instead of
// 'weak_odr' when they are not shared between codegen units
- // CHECK: define internal {{.*}}_ZN20internalize_closures4main{{.*}}$u7b$$u7b$closure$u7d$$u7d$
+ // FIXME(eddyb) `legacy` mangling uses `{{closure}}`, while `v0`
+ // uses `{closure#0}`, switch to the latter once `legacy` is gone.
+ // CHECK-LABEL: ; internalize_closures::main::{{.*}}closure
+ // CHECK-NEXT: ; Function Attrs:
+ // CHECK-NEXT: define internal
let c = |x:i32| { x + 1 };
let _ = c(1);
}
// This test makes sure that, when -Clink-dead-code is specified, we generate
// code for functions that would otherwise be skipped.
-// CHECK-LABEL: define hidden i32 @_ZN14link_dead_code8const_fn
+// CHECK-LABEL: ; link_dead_code::const_fn
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define hidden
const fn const_fn() -> i32 { 1 }
-// CHECK-LABEL: define hidden i32 @_ZN14link_dead_code9inline_fn
+// CHECK-LABEL: ; link_dead_code::inline_fn
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define hidden
#[inline]
fn inline_fn() -> i32 { 2 }
-// CHECK-LABEL: define hidden i32 @_ZN14link_dead_code10private_fn
+// CHECK-LABEL: ; link_dead_code::private_fn
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define hidden
fn private_fn() -> i32 { 3 }
// Check that local generics are internalized if they are in the same CGU
-// CHECK: define internal {{.*}} @_ZN34local_generics_in_exe_internalized3foo{{.*}}
+// CHECK-LABEL: ; local_generics_in_exe_internalized::foo
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define internal
pub fn foo<T>(x: T, y: T) -> (T, T) {
(x, y)
}
not_exported();
}
-// CHECK-LABEL: define {{.*}} @_ZN23target_cpu_on_functions12not_exported{{.*}}() {{.*}} #0
+// CHECK-LABEL: ; target_cpu_on_functions::not_exported
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define {{.*}}() {{.*}} #0
fn not_exported() {}
// CHECK: attributes #0 = {{.*}} "target-cpu"="{{.*}}"
# of types, it will not run with a dylib that has a different set of
# types.
+# NOTE(eddyb) this test only works with the `legacy` mangling,
+# and will probably get removed once `legacy` is gone.
+
all:
- $(RUSTC) a.rs --cfg x -C prefer-dynamic
- $(RUSTC) b.rs -C prefer-dynamic
+ $(RUSTC) a.rs --cfg x -C prefer-dynamic -Z symbol-mangling-version=legacy
+ $(RUSTC) b.rs -C prefer-dynamic -Z symbol-mangling-version=legacy
$(call RUN,b)
- $(RUSTC) a.rs --cfg y -C prefer-dynamic
+ $(RUSTC) a.rs --cfg y -C prefer-dynamic -Z symbol-mangling-version=legacy
$(call FAIL,b)
# The following command will:
# 1. dump the symbols of a library using `nm`
# 2. extract only those lines that we are interested in via `grep`
-# 3. from those lines, extract just the symbol name via `sed`
-# (symbol names always start with "_ZN" and end with "E")
+# 3. from those lines, extract just the symbol name via `sed`, which:
+# * always starts with "_ZN" and ends with "E" (`legacy` mangling)
+# * always starts with "_R" (`v0` mangling)
# 4. sort those symbol names for deterministic comparison
# 5. write the result into a file
dump-symbols = nm "$(TMPDIR)/lib$(1).rlib" \
| grep -E "$(2)" \
- | sed "s/.*\(_ZN.*E\).*/\1/" \
+ | sed -E "s/.*(_ZN.*E|_R[a-zA-Z0-9_]*).*/\1/" \
| sort \
> "$(TMPDIR)/$(1)$(3).nm"
COMBINED_CDYLIB_NAME=libcombined_rlib_dylib.dylib
endif
+# `grep` regex for symbols produced by either `legacy` or `v0` mangling
+RE_ANY_RUST_SYMBOL="_ZN.*h.*E\|_R[a-zA-Z0-9_]+"
+
all:
$(RUSTC) -Zshare-generics=no an_rlib.rs
$(RUSTC) -Zshare-generics=no a_cdylib.rs
# Check that a cdylib exports the public #[no_mangle] functions of dependencies
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
# Check that a cdylib DOES NOT export any public Rust functions
- [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ]
+ [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
# Check that a Rust dylib exports its monomorphic functions
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ]
- [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ]
+ [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rust_dylib)" -eq "1" ]
# Check that a Rust dylib does not export generics if -Zshare-generics=no
- [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "0" ]
+ [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "0" ]
# Check that a Rust dylib exports the monomorphic functions from its dependencies
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ]
# Check that a Rust dylib does not export generics if -Zshare-generics=no
- [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "0" ]
+ [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "0" ]
# Check that an executable does not export any dynamic symbols
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ]
# Check that a cdylib exports the public #[no_mangle] functions of dependencies
[ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
# Check that a cdylib DOES NOT export any public Rust functions
- [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ]
+ [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
$(RUSTC) -Zshare-generics=yes an_rlib.rs
# Check that a cdylib exports the public #[no_mangle] functions of dependencies
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
# Check that a cdylib DOES NOT export any public Rust functions
- [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ]
+ [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c $(RE_ANY_RUST_SYMBOL))" -eq "0" ]
# Check that a Rust dylib exports its monomorphic functions, including generics this time
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ]
- [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ]
- [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "1" ]
+ [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rust_dylib)" -eq "1" ]
+ [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "1" ]
# Check that a Rust dylib exports the monomorphic functions from its dependencies
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ]
- [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "1" ]
+ [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "1" ]
# Check that an executable does not export any dynamic symbols
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ]
// run-pass
#![allow(dead_code, unreachable_patterns)]
+#![allow(ellipsis_inclusive_range_patterns)]
struct Foo;
<Foo as HasNum>::NUM ... <Foo>::NUM => true,
_ => false,
});
+
+ assert!(match 2 {
+ Foo::NUM ..= 3 => true,
+ _ => false,
+ });
+ assert!(match 0 {
+ -1 ..= <Foo as HasNum>::NUM => true,
+ _ => false,
+ });
+ assert!(match 1 {
+ <Foo as HasNum>::NUM ..= <Foo>::NUM => true,
+ _ => false,
+ });
}
format!(" backtrace::{}", fn_name)
}
+fn contains_verbose_expected(s: &str, fn_name: &str) -> bool {
+ // HACK(eddyb) work around the fact that verbosely demangled stack traces
+ // (from `RUST_BACKTRACE=full`, or, as is the case here, panic-in-panic)
+ // may contain symbols with hashes in them, i.e. `backtrace[...]::`.
+ let prefix = " backtrace";
+ let suffix = &format!("::{}", fn_name);
+ s.match_indices(prefix).any(|(i, _)| {
+ s[i + prefix.len()..]
+ .trim_start_matches('[')
+ .trim_start_matches(char::is_alphanumeric)
+ .trim_start_matches(']')
+ .starts_with(suffix)
+ })
+}
+
fn runtest(me: &str) {
// Make sure that the stack trace is printed
let p = template(me).arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap();
let s = str::from_utf8(&out.stderr).unwrap();
// loosened the following from double::h to double:: due to
// spurious failures on mac, 32bit, optimized
- assert!(s.contains("stack backtrace") && s.contains(&expected("double")),
+ assert!(s.contains("stack backtrace") && contains_verbose_expected(s, "double"),
"bad output3: {}", s);
// Make sure a stack trace isn't printed too many times
// run-pass
// Parsing of range patterns
+#![allow(ellipsis_inclusive_range_patterns)]
+
const NUM1: i32 = 10;
mod m {
if let NUM1 ... m::NUM2 = 10 {} else { panic!() }
if let ::NUM1 ... ::m::NUM2 = 11 {} else { panic!() }
if let -13 ... -10 = 12 { panic!() } else {}
+
+ if let NUM1 ..= m::NUM2 = 10 {} else { panic!() }
+ if let ::NUM1 ..= ::m::NUM2 = 11 {} else { panic!() }
+ if let -13 ..= -10 = 12 { panic!() } else {}
}
-#![feature(const_int_conversion, reverse_bits)]
+#![feature(const_int_conversion)]
const REVERSE: u32 = 0x12345678_u32.reverse_bits();
const FROM_BE_BYTES: i32 = i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]);
data: RefCell::new(vec![])
}
}
- fn alloc(&self) -> Ptr {
+ fn alloc(&self) -> Ptr<'_> {
self.cur_ops.set(self.cur_ops.get() + 1);
if self.cur_ops.get() == self.failing_op {
data.push(true);
Ptr(addr, self)
}
+ // FIXME(#47949) Any use of this indicates a bug in rustc: we should never
+ // be leaking values in the cases here.
+ //
+ // Creates a `Ptr<'_>` and checks that the allocated value is leaked if the
+ // `failing_op` is in the list of exception.
+ fn alloc_leaked(&self, exceptions: Vec<usize>) -> Ptr<'_> {
+ let ptr = self.alloc();
+
+ if exceptions.iter().any(|operation| *operation == self.failing_op) {
+ let mut data = self.data.borrow_mut();
+ data[ptr.0] = false;
+ }
+ ptr
+ }
}
struct Ptr<'a>(usize, &'a Allocator);
let[_, _y..] = ar;
}
+fn panic_after_return(a: &Allocator) -> Ptr<'_> {
+ // Panic in the drop of `p` or `q` can leak
+ let exceptions = vec![8, 9];
+ a.alloc();
+ let p = a.alloc();
+ {
+ a.alloc();
+ let p = a.alloc();
+ // FIXME (#47949) We leak values when we panic in a destructor after
+ // evaluating an expression with `rustc_mir::build::Builder::into`.
+ a.alloc_leaked(exceptions)
+ }
+}
+
+fn panic_after_return_expr(a: &Allocator) -> Ptr<'_> {
+ // Panic in the drop of `p` or `q` can leak
+ let exceptions = vec![8, 9];
+ a.alloc();
+ let p = a.alloc();
+ {
+ a.alloc();
+ let q = a.alloc();
+ // FIXME (#47949)
+ return a.alloc_leaked(exceptions);
+ }
+}
+
+fn panic_after_init(a: &Allocator) {
+ // Panic in the drop of `r` can leak
+ let exceptions = vec![8];
+ a.alloc();
+ let p = a.alloc();
+ let q = {
+ a.alloc();
+ let r = a.alloc();
+ // FIXME (#47949)
+ a.alloc_leaked(exceptions)
+ };
+}
+
+fn panic_after_init_temp(a: &Allocator) {
+ // Panic in the drop of `r` can leak
+ let exceptions = vec![8];
+ a.alloc();
+ let p = a.alloc();
+ {
+ a.alloc();
+ let r = a.alloc();
+ // FIXME (#47949)
+ a.alloc_leaked(exceptions)
+ };
+}
+
+fn panic_after_init_by_loop(a: &Allocator) {
+ // Panic in the drop of `r` can leak
+ let exceptions = vec![8];
+ a.alloc();
+ let p = a.alloc();
+ let q = loop {
+ a.alloc();
+ let r = a.alloc();
+ // FIXME (#47949)
+ break a.alloc_leaked(exceptions);
+ };
+}
+
fn run_test<F>(mut f: F)
where F: FnMut(&Allocator)
{
run_test(|a| slice_pattern_reassign(a));
run_test(|a| subslice_pattern_reassign(a));
+ run_test(|a| {
+ panic_after_return(a);
+ });
+ run_test(|a| {
+ panic_after_return_expr(a);
+ });
+ run_test(|a| panic_after_init(a));
+ run_test(|a| panic_after_init_temp(a));
+ run_test(|a| panic_after_init_by_loop(a));
+
run_test_nopanic(|a| union1(a));
}
// Test old and new syntax for inclusive range patterns.
+#![allow(ellipsis_inclusive_range_patterns)]
+
fn main() {
assert!(match 42 { 0 ... 100 => true, _ => false });
assert!(match 42 { 0 ..= 100 => true, _ => false });
// run-pass
#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620
+#![allow(ellipsis_inclusive_range_patterns)]
// regression test for the model lexer handling the DOTDOTDOT syntax (#15877)
#![allow(dead_code)]
#![feature(core_intrinsics)]
+use std::fmt::Debug;
+
struct NT(str);
struct DST { a: u32, b: str }
+macro_rules! check {
+ (val: $ty_of:expr, $expected:expr) => {
+ assert_eq!(type_name_of_val($ty_of), $expected);
+ };
+ ($ty:ty, $expected:expr) => {
+ assert_eq!(unsafe { std::intrinsics::type_name::<$ty>()}, $expected);
+ };
+}
+
fn main() {
// type_name should support unsized types
- assert_eq!(unsafe {(
- // Slice
- std::intrinsics::type_name::<[u8]>(),
- // str
- std::intrinsics::type_name::<str>(),
- // Trait
- std::intrinsics::type_name::<dyn Send>(),
- // Newtype
- std::intrinsics::type_name::<NT>(),
- // DST
- std::intrinsics::type_name::<DST>()
- )}, ("[u8]", "str", "dyn std::marker::Send", "NT", "DST"));
+ check!([u8], "[u8]");
+ check!(str, "str");
+ check!(dyn Send, "dyn core::marker::Send");
+ check!(NT, "issue_21058::NT");
+ check!(DST, "issue_21058::DST");
+ check!(&i32, "&i32");
+ check!(&'static i32, "&i32");
+ check!((i32, u32), "(i32, u32)");
+ check!(val: foo(), "issue_21058::Foo");
+ check!(val: Foo::new, "issue_21058::Foo::new");
+ check!(val:
+ <Foo as Debug>::fmt,
+ "<issue_21058::Foo as core::fmt::Debug>::fmt"
+ );
+ check!(val: || {}, "issue_21058::main::{{closure}}");
+ bar::<i32>();
+}
+
+trait Trait {
+ type Assoc;
+}
+
+impl Trait for i32 {
+ type Assoc = String;
+}
+
+fn bar<T: Trait>() {
+ check!(T::Assoc, "alloc::string::String");
+ check!(T, "i32");
+}
+
+fn type_name_of_val<T>(_: T) -> &'static str {
+ unsafe { std::intrinsics::type_name::<T>() }
+}
+
+#[derive(Debug)]
+struct Foo;
+
+impl Foo {
+ fn new() -> Self { Foo }
+}
+
+fn foo() -> impl Debug {
+ Foo
}
#![allow(dead_code)]
fn test1(x: i8) -> i32 {
match x {
- 1...10 => 0,
+ 1..=10 => 0,
_ => 1,
}
}
--- /dev/null
+fn size_of_val<T>(_: &T) -> usize {
+ std::mem::size_of::<T>()
+}
+
+struct Foo(i64);
+
+// Test that the (symbol) mangling of `Foo` (the `struct` type) and that of
+// `typeof Foo` (the function type of the `struct` constructor) don't collide.
+fn main() {
+ size_of_val(&Foo(0));
+ size_of_val(&Foo);
+}
pub fn main() {
unsafe {
assert_eq!(type_name::<isize>(), "isize");
- assert_eq!(type_name::<Foo<usize>>(), "Foo<usize>");
+ assert_eq!(type_name::<Foo<usize>>(), "tydesc_name::Foo<usize>");
}
}
// ignore-tidy-linelength
pub trait Foo {
- // @has foo/trait.Foo.html '//h3[@id="tymethod.foo"]//div[@class="docblock attributes"]' '#[must_use]'
+ // @has foo/trait.Foo.html '//h3[@id="tymethod.foo"]//span[@class="docblock attributes"]' '#[must_use]'
#[must_use]
fn foo();
}
pub struct Bar;
impl Bar {
- // @has foo/struct.Bar.html '//h4[@id="method.bar"]//div[@class="docblock attributes"]' '#[must_use]'
+ // @has foo/struct.Bar.html '//h4[@id="method.bar"]//span[@class="docblock attributes"]' '#[must_use]'
#[must_use]
pub fn bar() {}
- // @has foo/struct.Bar.html '//h4[@id="method.bar2"]//div[@class="docblock attributes"]' '#[must_use]'
+ // @has foo/struct.Bar.html '//h4[@id="method.bar2"]//span[@class="docblock attributes"]' '#[must_use]'
#[must_use]
pub fn bar2() {}
}
}
}
-unsafe async fn unsafe_async_fn(x: u8) -> u8 {
+async unsafe fn unsafe_async_fn(x: u8) -> u8 {
wake_and_yield_once().await;
x
}
}
}
-unsafe async fn unsafe_async_fn(x: u8) -> u8 {
+async unsafe fn unsafe_async_fn(x: u8) -> u8 {
await!(wake_and_yield_once());
x
}
--- /dev/null
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct Foo<T, const N: usize>([T; {N}]);
+
+impl<T, const N: usize> Foo<T, {N}> {
+ fn foo(&self) -> usize {
+ {N}
+ }
+}
+
+fn main() {
+ let foo = Foo([0u32; 21]);
+ assert_eq!(foo.0, [0u32; 21]);
+ assert_eq!(foo.foo(), 21);
+}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+ --> $DIR/const-generic-array-wrapper.rs:3:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+
-#![feature(reverse_bits)]
-
fn main() {
let x: &'static i32 = &(5_i32.reverse_bits());
//~^ ERROR temporary value dropped while borrowed
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:4:28
+ --> $DIR/const-int-conversion.rs:2:28
|
LL | let x: &'static i32 = &(5_i32.reverse_bits());
| ------------ ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:6:28
+ --> $DIR/const-int-conversion.rs:4:28
|
LL | let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78]));
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:8:28
+ --> $DIR/const-int-conversion.rs:6:28
|
LL | let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78]));
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:10:28
+ --> $DIR/const-int-conversion.rs:8:28
|
LL | let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0])));
| ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:12:29
+ --> $DIR/const-int-conversion.rs:10:29
|
LL | let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes());
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:14:29
+ --> $DIR/const-int-conversion.rs:12:29
|
LL | let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes());
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/const-int-conversion.rs:16:29
+ --> $DIR/const-int-conversion.rs:14:29
|
LL | let d: &'static [u8] = &(i32::min_value().to_be().to_ne_bytes());
| ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
LL | println!("{}", a: &mut 4);
| ^ expecting a type here because of type ascription
|
- = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+ = note: #![feature(type_ascription)] lets you annotate an expression with a type: `<expr>: <type>`
note: this expression expects an ascribed type after the colon
--> $DIR/issue-22644.rs:34:20
|
LL | Test::Drill(field: 42);
| ^^ expecting a type here because of type ascription
|
- = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+ = note: #![feature(type_ascription)] lets you annotate an expression with a type: `<expr>: <type>`
note: this expression expects an ascribed type after the colon
--> $DIR/issue-34255-1.rs:8:17
|
LL | loop { break 'label: loop { break 'label 42; }; }
| ^^^^ expecting a type here because of type ascription
|
- = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+ = note: #![feature(type_ascription)] lets you annotate an expression with a type: `<expr>: <type>`
note: this expression expects an ascribed type after the colon
--> $DIR/lifetime_starts_expressions.rs:6:12
|
// compile-pass
+#![allow(ellipsis_inclusive_range_patterns)]
#![allow(unreachable_patterns)]
#![allow(unused_variables)]
#![warn(unused_parens)]
fn main() {
+ match 1 {
+ (_) => {} //~ WARNING: unnecessary parentheses around pattern
+ (y) => {} //~ WARNING: unnecessary parentheses around pattern
+ (ref r) => {} //~ WARNING: unnecessary parentheses around pattern
+ (e @ 1...2) => {} //~ WARNING: unnecessary parentheses around outer pattern
+ (1...2) => {} // Non ambiguous range pattern should not warn
+ e @ (3...4) => {} // Non ambiguous range pattern should not warn
+ }
+
+ match &1 {
+ (e @ &(1...2)) => {} //~ WARNING: unnecessary parentheses around outer pattern
+ &(_) => {} //~ WARNING: unnecessary parentheses around pattern
+ e @ &(1...2) => {} // Ambiguous range pattern should not warn
+ &(1...2) => {} // Ambiguous range pattern should not warn
+ }
+
+ match &1 {
+ e @ &(1...2) | e @ &(3...4) => {} // Complex ambiguous pattern should not warn
+ &_ => {}
+ }
+
match 1 {
(_) => {} //~ WARNING: unnecessary parentheses around pattern
(y) => {} //~ WARNING: unnecessary parentheses around pattern
}
match &1 {
- (e @ &(1...2)) => {} //~ WARNING: unnecessary parentheses around outer pattern
+ (e @ &(1..=2)) => {} //~ WARNING: unnecessary parentheses around outer pattern
&(_) => {} //~ WARNING: unnecessary parentheses around pattern
- e @ &(1...2) => {} // Ambiguous range pattern should not warn
+ e @ &(1..=2) => {} // Ambiguous range pattern should not warn
&(1..=2) => {} // Ambiguous range pattern should not warn
}
match &1 {
- e @ &(1...2) | e @ &(3..=4) => {} // Complex ambiguous pattern should not warn
+ e @ &(1..=2) | e @ &(3..=4) => {} // Complex ambiguous pattern should not warn
&_ => {}
}
}
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:9:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:10:9
|
LL | (_) => {}
| ^^^ help: remove these parentheses
|
note: lint level defined here
- --> $DIR/issue-54538-unused-parens-lint.rs:5:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:6:9
|
LL | #![warn(unused_parens)]
| ^^^^^^^^^^^^^
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:10:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:11:9
|
LL | (y) => {}
| ^^^ help: remove these parentheses
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:11:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:12:9
|
LL | (ref r) => {}
| ^^^^^^^ help: remove these parentheses
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:12:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:13:9
|
-LL | (e @ 1..=2) => {}
+LL | (e @ 1...2) => {}
| ^^^^^^^^^^^ help: remove these parentheses
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:18:9
+ --> $DIR/issue-54538-unused-parens-lint.rs:19:9
|
LL | (e @ &(1...2)) => {}
| ^^^^^^^^^^^^^^ help: remove these parentheses
warning: unnecessary parentheses around pattern
- --> $DIR/issue-54538-unused-parens-lint.rs:19:10
+ --> $DIR/issue-54538-unused-parens-lint.rs:20:10
+ |
+LL | &(_) => {}
+ | ^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:31:9
+ |
+LL | (_) => {}
+ | ^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:32:9
+ |
+LL | (y) => {}
+ | ^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:33:9
+ |
+LL | (ref r) => {}
+ | ^^^^^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:34:9
+ |
+LL | (e @ 1..=2) => {}
+ | ^^^^^^^^^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:40:9
+ |
+LL | (e @ &(1..=2)) => {}
+ | ^^^^^^^^^^^^^^ help: remove these parentheses
+
+warning: unnecessary parentheses around pattern
+ --> $DIR/issue-54538-unused-parens-lint.rs:41:10
|
LL | &(_) => {}
| ^^^ help: remove these parentheses
fn main() {
match 5 {
- 1 ... 10 => { }
- 5 ... 6 => { }
+ 1 ..= 10 => { }
+ 5 ..= 6 => { }
_ => {}
};
match 5 {
- 3 ... 6 => { }
- 4 ... 6 => { }
+ 3 ..= 6 => { }
+ 4 ..= 6 => { }
_ => {}
};
match 5 {
- 4 ... 6 => { }
- 4 ... 6 => { }
+ 4 ..= 6 => { }
+ 4 ..= 6 => { }
_ => {}
};
match 'c' {
- 'A' ... 'z' => {}
- 'a' ... 'z' => {}
+ 'A' ..= 'z' => {}
+ 'a' ..= 'z' => {}
_ => {}
};
match 1.0f64 {
- 0.01f64 ... 6.5f64 => {}
+ 0.01f64 ..= 6.5f64 => {}
0.02f64 => {}
_ => {}
};
error: unreachable pattern
--> $DIR/match-range-fail-dominate.rs:12:7
|
-LL | 5 ... 6 => { }
+LL | 5 ..= 6 => { }
| ^^^^^^^
|
note: lint level defined here
error: unreachable pattern
--> $DIR/match-range-fail-dominate.rs:18:7
|
-LL | 4 ... 6 => { }
+LL | 4 ..= 6 => { }
| ^^^^^^^
error: unreachable pattern
--> $DIR/match-range-fail-dominate.rs:24:7
|
-LL | 4 ... 6 => { }
+LL | 4 ..= 6 => { }
| ^^^^^^^
error: unreachable pattern
--> $DIR/match-range-fail-dominate.rs:30:7
|
-LL | 'a' ... 'z' => {}
+LL | 'a' ..= 'z' => {}
| ^^^^^^^^^^^
warning: floating-point types cannot be used in patterns
--> $DIR/match-range-fail-dominate.rs:35:7
|
-LL | 0.01f64 ... 6.5f64 => {}
+LL | 0.01f64 ..= 6.5f64 => {}
| ^^^^^^^
|
= note: #[warn(illegal_floating_point_literal_pattern)] on by default
warning: floating-point types cannot be used in patterns
--> $DIR/match-range-fail-dominate.rs:35:19
|
-LL | 0.01f64 ... 6.5f64 => {}
+LL | 0.01f64 ..= 6.5f64 => {}
| ^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
warning: floating-point types cannot be used in patterns
--> $DIR/match-range-fail-dominate.rs:35:7
|
-LL | 0.01f64 ... 6.5f64 => {}
+LL | 0.01f64 ..= 6.5f64 => {}
| ^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
fn digits(x: u8) -> u32 {
match x {
- OneDigit::FIRST...OneDigit::LAST => 1,
- TwoDigits::FIRST...TwoDigits::LAST => 2,
- ThreeDigits::FIRST...ThreeDigits::LAST => 3,
+ OneDigit::FIRST..=OneDigit::LAST => 1,
+ TwoDigits::FIRST..=TwoDigits::LAST => 2,
+ ThreeDigits::FIRST..=ThreeDigits::LAST => 3,
_ => unreachable!(),
}
}
LL | let x = Enum::Foo(a: 3, b: 4);
| ^ expecting a type here because of type ascription
|
- = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+ = note: #![feature(type_ascription)] lets you annotate an expression with a type: `<expr>: <type>`
note: this expression expects an ascribed type after the colon
--> $DIR/recover-from-bad-variant.rs:7:23
|
--- /dev/null
+error: symbol-name(_ZN5basic4main17hd72940ef9669d526E)
+ --> $DIR/basic.rs:7:1
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(basic::main::hd72940ef9669d526)
+ --> $DIR/basic.rs:7:1
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(basic::main)
+ --> $DIR/basic.rs:7:1
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: def-path(main)
+ --> $DIR/basic.rs:14:1
+ |
+LL | #[rustc_def_path]
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+// revisions: legacy v0
+//[legacy]compile-flags: -Z symbol-mangling-version=legacy
+ //[v0]compile-flags: -Z symbol-mangling-version=v0
+
#![feature(rustc_attrs)]
-#[rustc_symbol_name] //~ ERROR _ZN5basic4main
-#[rustc_def_path] //~ ERROR def-path(main)
+#[rustc_symbol_name]
+//[legacy]~^ ERROR symbol-name(_ZN5basic4main
+//[legacy]~| ERROR demangling(basic::main
+//[legacy]~| ERROR demangling-alt(basic::main)
+ //[v0]~^^^^ ERROR symbol-name(_RNvCs4fqI2P2rA04_5basic4main)
+ //[v0]~| ERROR demangling(basic[317d481089b8c8fe]::main)
+ //[v0]~| ERROR demangling-alt(basic::main)
+#[rustc_def_path]
+//[legacy]~^ ERROR def-path(main)
+ //[v0]~^^ ERROR def-path(main)
fn main() {
}
+++ /dev/null
-error: symbol-name(_ZN5basic4main17hd72940ef9669d526E)
- --> $DIR/basic.rs:3:1
- |
-LL | #[rustc_symbol_name]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: def-path(main)
- --> $DIR/basic.rs:4:1
- |
-LL | #[rustc_def_path]
- | ^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
--- /dev/null
+error: symbol-name(_RNvCs4fqI2P2rA04_5basic4main)
+ --> $DIR/basic.rs:7:1
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(basic[317d481089b8c8fe]::main)
+ --> $DIR/basic.rs:7:1
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(basic::main)
+ --> $DIR/basic.rs:7:1
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: def-path(main)
+ --> $DIR/basic.rs:14:1
+ |
+LL | #[rustc_def_path]
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+error: symbol-name(_ZN5impl13foo3Foo3bar17he53b9bee7600ed8dE)
+ --> $DIR/impl1.rs:13:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(impl1::foo::Foo::bar::he53b9bee7600ed8d)
+ --> $DIR/impl1.rs:13:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(impl1::foo::Foo::bar)
+ --> $DIR/impl1.rs:13:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: def-path(foo::Foo::bar)
+ --> $DIR/impl1.rs:20:9
+ |
+LL | #[rustc_def_path]
+ | ^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h86c41f0462d901d4E)
+ --> $DIR/impl1.rs:31:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(impl1::bar::<impl impl1::foo::Foo>::baz::h86c41f0462d901d4)
+ --> $DIR/impl1.rs:31:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
+ --> $DIR/impl1.rs:31:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: def-path(bar::<impl foo::Foo>::baz)
+ --> $DIR/impl1.rs:38:9
+ |
+LL | #[rustc_def_path]
+ | ^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_ZN198_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h6f205aef6a8ccc7bE)
+ --> $DIR/impl1.rs:63:13
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h6f205aef6a8ccc7b)
+ --> $DIR/impl1.rs:63:13
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method)
+ --> $DIR/impl1.rs:63:13
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
+ --> $DIR/impl1.rs:70:13
+ |
+LL | #[rustc_def_path]
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
+
-#![feature(rustc_attrs)]
+// ignore-tidy-linelength
+// revisions: legacy v0
+//[legacy]compile-flags: -Z symbol-mangling-version=legacy
+ //[v0]compile-flags: -Z symbol-mangling-version=v0
+
+#![feature(optin_builtin_traits, rustc_attrs)]
#![allow(dead_code)]
mod foo {
pub struct Foo { x: u32 }
impl Foo {
- #[rustc_symbol_name] //~ ERROR _ZN5impl13foo3Foo3bar
- #[rustc_def_path] //~ ERROR def-path(foo::Foo::bar)
+ #[rustc_symbol_name]
+ //[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar
+ //[legacy]~| ERROR demangling(impl1::foo::Foo::bar
+ //[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar)
+ //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13fooNtB2_3Foo3bar)
+ //[v0]~| ERROR demangling(<impl1[317d481089b8c8fe]::foo::Foo>::bar)
+ //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::bar)
+ #[rustc_def_path]
+ //[legacy]~^ ERROR def-path(foo::Foo::bar)
+ //[v0]~^^ ERROR def-path(foo::Foo::bar)
fn bar() { }
}
}
use foo::Foo;
impl Foo {
- #[rustc_symbol_name] //~ ERROR _ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
- #[rustc_def_path] //~ ERROR def-path(bar::<impl foo::Foo>::baz)
+ #[rustc_symbol_name]
+ //[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
+ //[legacy]~| ERROR demangling(impl1::bar::<impl impl1::foo::Foo>::baz
+ //[legacy]~| ERROR demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
+ //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13barNtNtB4_3foo3Foo3baz)
+ //[v0]~| ERROR demangling(<impl1[317d481089b8c8fe]::foo::Foo>::baz)
+ //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::baz)
+ #[rustc_def_path]
+ //[legacy]~^ ERROR def-path(bar::<impl foo::Foo>::baz)
+ //[v0]~^^ ERROR def-path(bar::<impl foo::Foo>::baz)
fn baz() { }
}
}
+trait Foo {
+ type Assoc;
+}
+
+auto trait AutoTrait {}
+
fn main() {
+ // Test closure mangling, and disambiguators.
+ || {};
+ || {
+ trait Bar {
+ fn method(&self) {}
+ }
+
+ // Test type mangling, by putting them in an `impl` header.
+ // FIXME(eddyb) test C varargs when `core::ffi::VaList` stops leaking into the signature
+ // (which is a problem because `core` has an unpredictable hash) - see also #44930.
+ impl Bar for [&'_ (dyn Foo<Assoc = extern fn(&u8, /*...*/)> + AutoTrait); 3] {
+ #[rustc_symbol_name]
+ //[legacy]~^ ERROR symbol-name(_ZN198_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method
+ //[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method
+ //[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method)
+ //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG0_KCRL0_hEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
+ //[v0]~| ERROR demangling(<[&dyn impl1[317d481089b8c8fe]::Foo<Assoc = for<'a, 'b> extern "C" fn(&'b u8)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method)
+ //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a, 'b> extern "C" fn(&'b u8)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
+ #[rustc_def_path]
+ //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
+ //[v0]~^^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
+ fn method(&self) {}
+ }
+ };
}
+++ /dev/null
-error: symbol-name(_ZN5impl13foo3Foo3bar17he53b9bee7600ed8dE)
- --> $DIR/impl1.rs:8:9
- |
-LL | #[rustc_symbol_name]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: def-path(foo::Foo::bar)
- --> $DIR/impl1.rs:9:9
- |
-LL | #[rustc_def_path]
- | ^^^^^^^^^^^^^^^^^
-
-error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h86c41f0462d901d4E)
- --> $DIR/impl1.rs:18:9
- |
-LL | #[rustc_symbol_name]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: def-path(bar::<impl foo::Foo>::baz)
- --> $DIR/impl1.rs:19:9
- |
-LL | #[rustc_def_path]
- | ^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
-
--- /dev/null
+error: symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13fooNtB2_3Foo3bar)
+ --> $DIR/impl1.rs:13:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<impl1[317d481089b8c8fe]::foo::Foo>::bar)
+ --> $DIR/impl1.rs:13:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<impl1::foo::Foo>::bar)
+ --> $DIR/impl1.rs:13:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: def-path(foo::Foo::bar)
+ --> $DIR/impl1.rs:20:9
+ |
+LL | #[rustc_def_path]
+ | ^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RNvMNtCs4fqI2P2rA04_5impl13barNtNtB4_3foo3Foo3baz)
+ --> $DIR/impl1.rs:31:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<impl1[317d481089b8c8fe]::foo::Foo>::baz)
+ --> $DIR/impl1.rs:31:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<impl1::foo::Foo>::baz)
+ --> $DIR/impl1.rs:31:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: def-path(bar::<impl foo::Foo>::baz)
+ --> $DIR/impl1.rs:38:9
+ |
+LL | #[rustc_def_path]
+ | ^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RNvXNCNvCs4fqI2P2rA04_5impl14mains_0ARDNtB6_3Foop5AssocFG0_KCRL0_hEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
+ --> $DIR/impl1.rs:63:13
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<[&dyn impl1[317d481089b8c8fe]::Foo<Assoc = for<'a, 'b> extern "C" fn(&'b u8)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method)
+ --> $DIR/impl1.rs:63:13
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a, 'b> extern "C" fn(&'b u8)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
+ --> $DIR/impl1.rs:63:13
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8)> + AutoTrait; _] as main::{{closure}}#1::Bar>::method)
+ --> $DIR/impl1.rs:70:13
+ |
+LL | #[rustc_def_path]
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
+
--- /dev/null
+error: symbol-name(_ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo17h059a991a004536adE)
+ --> $DIR/issue-60925.rs:21:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(issue_60925::foo::Foo<issue_60925::llv$6d$..Foo$GT$::foo::h059a991a004536ad)
+ --> $DIR/issue-60925.rs:21:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(issue_60925::foo::Foo<issue_60925::llv$6d$..Foo$GT$::foo)
+ --> $DIR/issue-60925.rs:21:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+// ignore-tidy-linelength
+// revisions: legacy v0
+//[legacy]compile-flags: -Z symbol-mangling-version=legacy
+ //[v0]compile-flags: -Z symbol-mangling-version=v0
+
#![feature(rustc_attrs)]
// This test is the same code as in ui/issue-53912.rs but this test checks that the symbol mangling
// fix produces the correct result, whereas that test just checks that the reproduction compiles
-// successfully and doesn't segfault
+// successfully and doesn't crash LLVM
fn dummy() {}
impl Foo<::llvm::Foo> {
#[rustc_symbol_name]
-//~^ ERROR _ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo17h059a991a004536adE
+ //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo36Foo$LT$issue_60925..llv$6d$..Foo$GT$3foo
+ //[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llv$6d$..Foo$GT$::foo
+ //[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo<issue_60925::llv$6d$..Foo$GT$::foo)
+ //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs4fqI2P2rA04_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
+ //[v0]~| ERROR demangling(<issue_60925[317d481089b8c8fe]::foo::Foo<issue_60925[317d481089b8c8fe]::llvm::Foo>>::foo)
+ //[v0]~| ERROR demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo)
pub(crate) fn foo() {
for _ in 0..0 {
for _ in &[::dummy()] {
LL | #[rustc_symbol_name]
| ^^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: demangling(issue_60925::foo::Foo<issue_60925::llv$6d$..Foo$GT$::foo::h059a991a004536ad)
+ --> $DIR/issue-60925.rs:16:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(issue_60925::foo::Foo<issue_60925::llv$6d$..Foo$GT$::foo)
+ --> $DIR/issue-60925.rs:16:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
--- /dev/null
+error: symbol-name(_RNvMNtCs4fqI2P2rA04_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
+ --> $DIR/issue-60925.rs:21:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<issue_60925[317d481089b8c8fe]::foo::Foo<issue_60925[317d481089b8c8fe]::llvm::Foo>>::foo)
+ --> $DIR/issue-60925.rs:21:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo)
+ --> $DIR/issue-60925.rs:21:9
+ |
+LL | #[rustc_symbol_name]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
LL | println!("test"): 0;
| ^ expecting a type here because of type ascription
|
- = note: type ascription is a nightly-only feature that lets you annotate an expression with a type: `<expr>: <type>`
+ = note: #![feature(type_ascription)] lets you annotate an expression with a type: `<expr>: <type>`
note: this expression expects an ascribed type after the colon
--> $DIR/type-ascription-instead-of-statement-end.rs:9:5
|
-Subproject commit fb33fad08e8f08c032b443bab0df299ce22fe61b
+Subproject commit d2f51228152a139a2a8aaba59b8a4e68f498ff26